У меня есть база данных Access, которую я конвертирую в базу данных SQL, используя sqlbulkcopy в vb.net. У нас есть значения валюты (до двух знаков после запятой), которые хранятся в Access как Double. Когда я конвертирую эти поля Access в SQL-поля с типом [десятичное] (19, 2), число, подобное 81.6, хранящееся в поле Access, иногда появляется как 81.59 в поле SQL при преобразовании.
Если я изменил тип в SQL на [десятичный] (19,4), то он отобразится как 81.5999. Число в Access определенно рассчитано и сохранено не более чем двумя знаками после запятой. Может кто-нибудь объяснить мне, почему SQL это делает? Это не происходит все время ... только в некоторых записях.
Я просмотрел практически любую статью, которую я смог найти, которая объясняет десятичные типы, и я понимаю, что такое десятичное число (я думаю), но я не понимаю, почему числа иногда преобразуются так. Спасибо за вашу помощь.
EDIT: Вот код, который я упомянул ниже, который я использовал для прокрутки всех таблиц и столбцов, чтобы переименовать столбцы с псевдонимом, заканчивающиеся на «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
Ваша проблема заключается в том , что типы с плавающей точкой , как Double
часто не могут хранить номера точно, даже ценности , которые кажутся довольно «простое» число к нам людям. Это можно продемонстрировать, введя следующее в окно Immediate окна редактора VBA в Access:
?(CDbl(81.60) * CDbl(100)) - CDbl(8160)
Полученный результат
-5.6843418860808E-13
Ваш опыт показывает, что прямая передача Access Double
to SQL Server decimal
будет усекать номер вместо округления его. Поэтому вам нужно скопировать значения из Access в отдельный столбец SQL Server типа float
, а затем использовать запрос UPDATE в SQL Server для заполнения decimal(19,2)
столбца decimal(19,2)
, например,
UPDATE TableName SET DecimalColumn = ROUND(FloatColumn, 2)
В случае, если это упростит работу, также необходимо сделать округление и преобразование на стороне доступа. Вы можете создать запрос 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
... приводит к ошибке
Циклическая ссылка вызывает псевдоним «UnitPrice» в списке SELECT для определения запроса
Обходной путь для этой проблемы заключается в использовании такого запроса:
SELECT ProductID, ProductName, CurrUnitPrice AS UnitPrice
FROM
(
SELECT ProductID, ProductName, CCur(Round([UnitPrice],2)) AS CurrUnitPrice
FROM Products
)