2014-04-22 13 views
7

Software utilizzato: Windows 7 64 bit Ultimate, .Net 4, SQL Server 2008 R2 .Strambo "OLE DB provider" STREAM "per server collegato" (null) "ha restituito dati non validi per la colonna" [! BulkInsert] .Valore "errore

SELECT @@ vERSION restituisce:

Microsoft SQL Server 2008 R2 (RTM) - 10.50.1617.0 (X64) Apr 22 2011 19:23:43 Copyright (c) Microsoft Corporation Developer Edition (64-bit) on Windows NT 6.1 <X64> (Build 7601: Service Pack 1) (Hypervisor) 

di riprodursi, e supponendo che si dispone di un server SQL locale 2008 R2 esempio, incollare il seguente codice nel LINQPad ed eseguirlo come un programma

. Scoppia con:

Il provider OLE DB "STREAM" per il server collegato "(null)" ha restituito dati non validi per la colonna "[! BulkInsert] .Value".

void Main() 
{ 
    SqlConnection cn = new SqlConnection("data source=localhost;Integrated Security=SSPI;initial catalog=tempdb;Connect Timeout=180;"); 
    cn.Open(); 

    IList<decimal> list = new List<decimal>() {-8m, 8m}; 

    decimal result = list.Sum(x => x); 

    Console.WriteLine(result == 0); 

    string tableName = "#test"; 

    CreateTemporaryTable(cn, tableName, 
     String.Format(@" 
      create table {0} (
      Value sql_variant 
     ); 
     ", tableName)); 

    SqlBulkCopy sqlBulkCopy = new SqlBulkCopy(cn); 
    sqlBulkCopy.DestinationTableName = tableName;  

    DataTable dt = new DataTable(); 
    dt.Columns.Add("Value", typeof(object)); 
    dt.Rows.Add(result); 
    sqlBulkCopy.WriteToServer(dt); 

    sqlBulkCopy.Close(); 

    cn.Close(); 
} 

// Define other methods and classes here 


public static void CreateTemporaryTable(SqlConnection cn, string destinationTableName, string createTableStatement) 
{ 
    string objectIdValue = (destinationTableName.StartsWith("#") ? "tempdb.." : "") + destinationTableName; 
    string sql = String.Format(@" 
    if (object_id (N'{0}', N'U') is not null) 
     begin 
     drop table {1}; 
     end; 
     {2}  
     ", objectIdValue, destinationTableName, createTableStatement); 

//  Console.WriteLine(sql); 
    SqlCommand cmd = new SqlCommand(sql, cn); 
    try 
    { 
    cmd.ExecuteNonQuery(); 
    } 
    finally 
    { 
    cmd.Dispose(); 
    } 
} 

io probabilmente creare un caso con Microsoft, ma ero curioso di vedere se qualcun altro ha visto questo prima, e se ci sono eventuali soluzioni alternative. Sembra che non tutti gli zeri siano creati uguali.

Solo un aggiornamento:

ho aperto un caso con Microsoft. Ci sono voluti quasi 2 mesi per ottenere qualche oscuro flag dbcc non documentato che disabilita la convalida dei valori che vengono pompati tramite la copia bulk nella colonna variant. Il caso è stato rimbalzato tra i diversi team (il supporto è stato fornito da appaltatori privati ​​indiani) e non hanno mai avuto il problema di root che penso sia legato al valore prodotto dalle seguenti righe e come sia gestito dal codice di copia bulk :

Quindi, per concludere, è stato deludente e ho rinunciato perché è un evento raro.

risposta

3

La soluzione indicato da Microsoft e che ho finito per utilizzare, è quello di utilizzare questo flag non documentato: DBCC TRACEON (7307, -1). È possibile abilitarlo a livello di connessione o a livello di server.

14

Se il tipo di dati per il "valore" della colonna è float, il problema probabile è che si invii un server double.NaN a sql, che non gradisce.

Si prega di notare che una chiamata come Double.TryParse ("nan", fuori dv) sarà felice di tornare vero e impostare il dv a Double.NaN

Spero che questo aiuti, K.

+0

Il tipo di colonna è sql_variant. – costa

+0

non so se le colonne sqlvariant possono memorizzare NaN ma puoi cambiare il tipo di colonna in varchar per vedere se l'errore persiste. –

+0

Non voglio cambiarlo in varchar perché deve essere sql_variant. – costa

0

Questo errore viene generato se double.NaN si trova nella tabella, quindi convertire in null.

Ho utilizzato questo metodo di estensione per risolvere questo problema.

Per utilizzare, aggiungere .MyToNullIfNan() a qualsiasi double o double?, e produrrà un double? che è null se NaN.

public static class MyToNullIfNanExtension 
{ 
    public static double? MyToNullIfNan(this double? result) 
    { 
     if (result.HasValue) 
     { 
      if (double.IsNaN(result.Value) || double.IsInfinity(result.Value)) 
      { 
       return null; 
      } 
     } 
     return result; 
    } 

    public static double? MyToNullIfNan(this double result) 
    { 
     if (double.IsNaN(result) || double.IsInfinity(result)) 
     { 
      return null; 
     } 
     return result; 
    } 
} 
+1

La radice del problema qui è che 8m e -8m quando inseriti in una lista e riepilogati usando linq, producono una somma che non può essere salvata tramite SqlBulkCopy. Microsoft non ha fornito una correzione adeguata. Si prega di notare che ho dovuto usare il tipo decimale e non il doppio. – costa

+0

Grazie. Nel mio caso, il problema era che 'double.NaN' non può essere salvato nel database. La soluzione è convertirli invece in null. – Contango

Problemi correlati