When I insert decimal values into Sql Server 2005 from a C# DataTable using bulk copy the values get truncated instead of rounded.
The code I'm using is pretty simple:
var bulkCopy = new SqlBulkCopy(connection, SqlBulkCopyOptions.Default, null) { DestinationTableName = tableName};
bulkCopy.WriteToServer(dataTable);
Does anyone know how to fix this?
The TRUNCATE() function truncates a number to the specified number of decimal places.
Standard SQL requires that DECIMAL(5,2) be able to store any value with five digits and two decimals, so values that can be stored in the salary column range from -999.99 to 999.99 . In standard SQL, the syntax DECIMAL( M ) is equivalent to DECIMAL( M ,0) .
The SqlBulkCopy class lets you write managed code solutions that provide similar functionality. There are other ways to load data into a SQL Server table (INSERT statements, for example), but SqlBulkCopy offers a significant performance advantage over them.
As we know from before, integers are whole numbers, or numbers with no fractions (i.e. no decimal places). This is going to be in the test later, so pay attention. In other words, the numbers 0 through 9 are integers, but a floating point or decimal / numeric value is not an integer.
According to the reference source, SqlBulkCopy
always truncates decimal values instead of rounding, which unfortunately differs from the behavior of the BULK INSERT statement.
The private ConvertValue
method calls TdsParser.AdjustSqlDecimalScale
if the scale of the source value differs from the scale of the destination column:
switch(type.NullableType) {
case TdsEnums.SQLNUMERICN:
case TdsEnums.SQLDECIMALN:
// ...
if (sqlValue.Scale != metadata.scale) {
sqlValue = TdsParser.AdjustSqlDecimalScale(sqlValue, metadata.scale);
}
AdjustSqlDecimalScale
in turn calls SqlDecimal.AdjustScale
, passing false
for fRound
:
static internal SqlDecimal AdjustSqlDecimalScale(SqlDecimal d, int newScale) {
if (d.Scale != newScale) {
return SqlDecimal.AdjustScale(d, newScale - d.Scale, false /* Don't round, truncate. MDAC 69229 */);
}
return d;
}
There's apparently no way to override this behavior and pass true
to AdjustScale
, so if you want to use SqlBulkCopy
, you will need to round the values in the DataTable
yourself before calling WriteToServer
.
Alternatively, you could write the data to a file and execute BULK INSERT directly, forgoing SqlBulkCopy
.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With