【发布时间】:2022-03-16 22:12:07
【问题描述】:
我有代码使用SqlBulkCopy克隆了很多表,以前可以,但是很奇怪,最近出现异常
从 bcp 客户端收到无效的 colid 列长度
我已经搜索了这个异常,但仍然没有解决我的问题。
sqlBulkCopy.WriteToServer(reader) 将引发此异常,如果一个表有两个连续的列,它们都是Char(1) 或nvarchar(nn) 类型,并且都具有NULL。有时,更改SqlBulkCopy.BatchSize 可以使其工作,但很多时候,它不会。
简化后,我有如下测试用例,可以在两台服务器上重现:
-
创建如下表:(在 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 -
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