【问题标题】:SqlBulkCopy got exception : "Received an invalid column length from the bcp client for colid ."SqlBulkCopy 出现异常:“从 bcp 客户端接收到 colid 的无效列长度。”
【发布时间】:2022-03-16 22:12:07
【问题描述】:

我有代码使用SqlBulkCopy克隆了很多表,以前可以,但是很奇怪,最近出现异常

从 bcp 客户端收到无效的 colid 列长度

我已经搜索了这个异常,但仍然没有解决我的问题。

sqlBulkCopy.WriteToServer(reader) 将引发此异常,如果一个表有两个连续的列,它们都是Char(1)nvarchar(nn) 类型,并且都具有NULL。有时,更改SqlBulkCopy.BatchSize 可以使其工作,但很多时候,它不会。

简化后,我有如下测试用例,可以在两台服务器上重现:

  1. 创建如下表:(在 SQL Server 2012 SP 4 和 SQL Server 2016 SP2 上测试)

     IF OBJECT_ID('dbo.TestTable', 'U') IS NOT NULL
         DROP TABLE dbo.TestTable;
    
     CREATE TABLE [dbo].[TestTable]
     (
         [value2] [char](1) NULL,
         [value1] [char](1) NULL
     ) ON [PRIMARY]
     GO
    
    
     DECLARE @i int = 0
    
     WHILE @i < 262
     BEGIN
         SET @i = @i + 1
    
         INSERT INTO [dbo].[TestTable]([value2], [value1]) 
         VALUES (null, null)
     END
    
  2. C#控制台(.net framework 4.7)代码如下

     class Program
     {
         // [change here] 
         static string sourceConn = @"Server={YourServer};Database={YourDatabase};User ID={userYourName};Password={yourPassword};connect timeout=15";
    
         static void Main(string[] args)
         {
             CopyTable(sourceConn, sourceConn, "TestTable", "testTableBAK");
             Console.ReadLine();
         }
    
         static void CopyTable(string sConnSource, string sConnDest, string sTableSource, string sTableDest)
         {
             if (IsTableExist(sConnDest, sTableDest))
             {
                 RunNonQuerySQL(sConnDest, "DROP TABLE " + sTableDest);
                 Console.WriteLine($"existing table  {sTableDest} dropped");
             }
    
             CopySchema(sConnDest, sTableSource, sTableDest);
    
             using (SqlConnection connSource = new SqlConnection(sConnSource))
             {
                 connSource.Open();
                 SqlCommand cmd = new SqlCommand();
                 cmd.Connection = connSource;
                 cmd.CommandText = "SELECT * FROM " + sTableSource;
    
                 // using (SqlBulkCopy sqlBulkCopy = new SqlBulkCopy(sConnDest, SqlBulkCopyOptions.KeepNulls | SqlBulkCopyOptions.KeepIdentity))
                 using (SqlBulkCopy sqlBulkCopy = new SqlBulkCopy(sConnDest))
                 {
                     // sqlBulkCopy.BatchSize = 1380; // this optional setting will work if set value smaller than 1397 for testTable on my new server (SQL server  13.0.5102.14)
                     // sqlBulkCopy.BatchSize = 261; // this optional setting will work if set value smaller than 261 for testTable on 2 older server (SQL server  11.0.7001)
                     sqlBulkCopy.DestinationTableName = sTableDest;
                     SqlDataReader reader = cmd.ExecuteReader();
    
                     try
                     {
                         // exception here 
                         sqlBulkCopy.WriteToServer(reader);  
                         Console.WriteLine("table copied");
                     }
                     catch (SqlException ex)
                     {
                         Console.WriteLine(ex.Message);
                     }
    
                     sqlBulkCopy.Close();
                 }
             }
         }
    
         static bool IsTableExist(string sConn, string sTableName)
         {
             bool result = false;
    
             using (SqlConnection conn = new SqlConnection(sConn))
             {
                 conn.Open();
                 SqlCommand cmd = new SqlCommand();
                 string[] s = sTableName.Split('.');
    
                 if (s.Length > 1)
                 {
                     cmd.CommandText = "select count (*) as counter from information_schema.tables where table_name = '" + s[1] + "' and TABLE_SCHEMA='" + s[0] + "'";
                 }
                 else
                 {
                     cmd.CommandText = "select count (*) as counter from information_schema.tables  where table_name = '" + sTableName + "'";
                 }
                 cmd.Connection = conn;
                 var count = Convert.ToInt32(cmd.ExecuteScalar());
                 result = count > 0;
             }
    
             return result;
         }
    
         static bool RunNonQuerySQL(string sConn, string sSQL)
         {
             bool result = false;
    
             using (SqlConnection conn = new SqlConnection(sConn))
             {
                 conn.Open();
    
                 SqlCommand cmd = new SqlCommand();
                 cmd.CommandText = sSQL;
                 cmd.Connection = conn;
    
                 var count = cmd.ExecuteNonQuery();
                 result = true;
             }
    
             return result;
         }
    
         static public bool CopySchema(string sConn, string sTableSource, string sTableDest)
         {
             return RunQuerySQL(sConn, "select * into " + sTableDest + " from " + sTableSource + " where 1=2");
         }
    
         static public bool RunQuerySQL(string sConn, string sSQL)
         {
             using (SqlConnection conn = new SqlConnection(sConn))
             {
                 conn.Open();
    
                 SqlCommand cmd = new SqlCommand();
                 cmd.CommandText = sSQL;
                 cmd.Connection = conn;
    
                 SqlDataReader reader = cmd.ExecuteReader();
    
                 if (reader.Read())
                 {
                     return true;
                 }
                 else
                 {
                     return false;
                 }
             }
         }
     }
    

【问题讨论】:

  • erm,RunNonQuerySQL() 总是返回 true 或者可能抛出。这没有任何意义。
  • 如果您有任何 VARCHAR 小于 4 的列,请注意数据中的 NULL 被误解为 4char 字符串“NULL”
  • 旁白:你应该使用using来处理你的命令和读者
  • 嗨,米奇,我已经阅读了你上面给出的链接,但它与我的情况不同,它是从 csv 文件导入的,数据长度比定义的列长。

标签: c# sql-server bcp


【解决方案1】:

我刚刚遇到了这个错误。

我尝试将长度为 5 的字符串插入到定义为“varchar(4)”的表列中。

我的错误信息是: “从 bcp 客户端收到一个无效的列长度,用于 colid 2”。

“Colid 2”指的是行的第二列 (DataRow),它是 DataTable 的一部分,我用作调用 SqlBulkCopy.WriteToServer(DataTable table) 方法的参数。

在我的情况下,解决方案是在尝试调用 SqlBulkCopy.WriteToServer() 之前添加验证代码,检查输入数据中字符串的长度。

【讨论】:

    猜你喜欢
    • 2012-05-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-11-09
    • 1970-01-01
    • 1970-01-01
    • 2013-06-05
    相关资源
    最近更新 更多