Accesso doppio al decimale SQL utilizzando SQL Bulk Copy

ms-access sql sqlbulkcopy vb.net

Domanda

Ho un database di Access che sto convertendo in un database SQL usando sqlbulkcopy in vb.net. Abbiamo valori di valuta (fino a 2 posizioni decimali) memorizzati in Access come Double. Quando converto questi campi di accesso in campi SQL con tipo [decimale] (19, 2), un numero come 81.6 memorizzato nel campo Accesso talvolta appare come 81.59 nel campo SQL quando convertito.

Se cambio il tipo in SQL in [decimale] (19,4), allora viene visualizzato come 81.5999. Il numero in Access è sicuramente calcolato e memorizzato in non più di due posizioni decimali. Qualcuno può spiegarmi perché SQL sta facendo questo? Non succede tutto il tempo ... solo in alcuni record.

Ho esaminato quasi tutti gli articoli che ho trovato che spiegano i tipi decimali e capisco cos'è il decimale (credo), ma non capisco perché i numeri a volte vengano convertiti in questo modo. Grazie per l'aiuto.

EDIT: Ecco il codice che ho citato di seguito che ho usato per scorrere tutte le tabelle e le colonne per rinominare le colonne con alias che finiscono in "1Z" ai loro nomi originali:

        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

Risposta accettata

Il tuo problema è che i tipi a virgola mobile come Double spesso non possono memorizzare esattamente i numeri, anche i valori che sembrano essere numeri "semplici" per noi umani. Questo può essere dimostrato digitando quanto segue nella finestra immediata dell'editor VBA in Access:

?(CDbl(81.60) * CDbl(100)) - CDbl(8160)

Il risultato restituito è

-5.6843418860808E-13

La tua esperienza suggerisce che un trasferimento diretto di Access Double a SQL Server decimal troncerà il numero invece di arrotondarlo. Pertanto, è necessario copiare i valori da Access in una colonna SQL Server separata di tipo float e quindi utilizzare una query UPDATE in SQL Server per compilare la colonna decimal(19,2) , ad esempio,

UPDATE TableName SET DecimalColumn = ROUND(FloatColumn, 2)

modificare

Nel caso in cui rende le cose più semplici, dovrebbe anche essere possibile fare l'arrotondamento e la conversione sul lato di accesso. Puoi creare una query di selezione per ogni tabella che arrotonda i valori monetari e li converte in Currency , come questo ...

SELECT ProductID, ProductName, CCur(Round([UnitPrice],2)) AS CurrUnitPrice
FROM Products;

... e quindi SqlBulkCopy la query anziché la tabella.

modificare

Come forse hai scoperto, prova a convertire una colonna mantenendo il nome della colonna originale con una query come ...

SELECT ProductID, ProductName, CCur(Round([UnitPrice],2)) AS UnitPrice
FROM Products

... genera l'errore

Riferimento circolare causa da alias "PrezzoUnitario" nell'elenco SELECT della query definition

Una soluzione alternativa a tale problema sarebbe utilizzare una query come questa:

SELECT ProductID, ProductName, CurrUnitPrice AS UnitPrice
FROM
(
    SELECT ProductID, ProductName, CCur(Round([UnitPrice],2)) AS CurrUnitPrice
    FROM Products
)


Autorizzato sotto: CC-BY-SA with attribution
Non affiliato con Stack Overflow
Autorizzato sotto: CC-BY-SA with attribution
Non affiliato con Stack Overflow