我有一个Access数据库,我在vb.net中使用sqlbulkcopy转换为SQL数据库。我们在Access as Double中存储了货币值(最多2个小数位)。当我将这些Access字段转换为类型为[decimal](19,2)的SQL字段时,存储在Access字段中的数字81.6有时在转换时在SQL字段中显示为81.59。
如果我将SQL中的类型更改为[decimal](19,4),则显示为81.5999。 Access中的数字肯定是计算并存储到不超过两位小数。有人可以向我解释为什么SQL会这样做吗?它不会一直发生......只在某些记录中发生。
我已经回顾了我能找到的解释小数类型的任何文章,我理解小数是什么(我认为),但我不明白为什么数字有时会像这样转换。谢谢你的帮助。
修改 以下是我在下面提到的代码,我用来循环遍历所有表和列,将以“1Z”结尾的别名列重命名为原始名称:
Dim dtTbls As DataTable = cnnSQL.GetSchema("Tables")
For Each drTbls As DataRow In dtTbls.Rows
Dim sTableName As String = drTbls(2)
Dim query As String = String.Concat("select * from [", sTableName, "] Where 0=1")
Dim myCmd As SqlDataAdapter = New SqlDataAdapter(query, cnnSQL)
Dim myData As New DataSet()
myCmd.Fill(myData)
For Each colu As DataColumn In myData.Tables(0).Columns
If colu.ColumnName.EndsWith("1Z") = True Then
Dim sNewColName As String = colu.ColumnName.Remove(colu.ColumnName.Length - 2, 2)
dbSQL.ExecuteNonQuery(String.Concat("EXEC sp_rename '", sTableName, ".", colu.ColumnName, "', '", sNewColName, "', 'COLUMN'"))
End If
Next colu
Next drTbls
答案 0 :(得分:1)
你的问题是像Double
这样的浮点类型通常无法存储完全的数字,甚至是对我们人类来说似乎是非常“简单”数字的值。这可以通过在Access中的VBA编辑器的立即窗口中键入以下内容来证明:
?(CDbl(81.60) * CDbl(100)) - CDbl(8160)
返回的结果是
-5.6843418860808E-13
您的经验表明,将Access Double
直接转移到SQL Server decimal
会截断数字而不是舍入数字。因此,您需要做的是将Access中的值复制到类型为float
的单独SQL Server列中,然后在SQL Server中使用UPDATE查询来填充decimal(19,2)
列,例如,
UPDATE TableName SET DecimalColumn = ROUND(FloatColumn, 2)
如果它使事情变得更容易,也应该可以在Access端进行舍入和转换。您可以为每个汇总货币值的表创建一个Select查询,并将它们转换为Currency
,就像这样......
SELECT ProductID, ProductName, CCur(Round([UnitPrice],2)) AS CurrUnitPrice
FROM Products;
...然后SqlBulkCopy
查询而不是表格。
正如您可能已经发现的那样,尝试转换列,同时使用类似...
之类的查询保留原始列名称SELECT ProductID, ProductName, CCur(Round([UnitPrice],2)) AS UnitPrice
FROM Products
...导致错误
循环引用由查询定义的SELECT列表中的别名'UnitPrice'引起
该问题的解决方法是使用如下查询:
SELECT ProductID, ProductName, CurrUnitPrice AS UnitPrice
FROM
(
SELECT ProductID, ProductName, CCur(Round([UnitPrice],2)) AS CurrUnitPrice
FROM Products
)