[编程笔记] 从 bcp 客户端收到一个对 colid 7 无效的列长度

    最近在做一个工具改造,实现A库数据导B库的功能。今天遇到一个奇怪问题,“从 bcp 客户端收到一个对 colid 7 无效的列长度”。

    代码是从A库执行SELECT语句到本地DataTable,再将DataTable插入到B库,插入的过程是通过SqlBulkCopy实现的,这样做的好处是不用写INSERT语句,只要DataTable的列名和B库表中列名一致,则传入DataTable直接插入即可。

    这里贴一下工具方法,有需要的可以参考一下:

public class DataHandler
{
    /// <summary>
    /// 把DataTable中数据快速插入指定表中
    /// </summary>
    /// <param name="connectionString">目标连接字符</param>
    /// <param name="tableName">目标表(数据库表名)</param>
    /// <param name="dataSource">源数据</param>
    public void SqlBulkCopyByDatatable(string connectionString, string tableName, DataTable dataSource, ref string msg)
    {
        SqlTransaction tran = null;//声明一个事务对象
        using (SqlConnection conn = new SqlConnection(connectionString))
        {
            conn.Open();
            using (tran = conn.BeginTransaction())
            {
                using (SqlBulkCopy sqlbulkcopy = new SqlBulkCopy(conn, SqlBulkCopyOptions.Default, tran))
                {
                    try
                    {
                        sqlbulkcopy.DestinationTableName = tableName;
                        sqlbulkcopy.BatchSize = 100;
                        // 这里的Dt处理一下,删掉RID,避免列不一致导致插入失败
                        if (dataSource.Columns.Contains("RID"))
                        {
                            dataSource.Columns.Remove("RID");
                        }
                        // 设置列映射
                        for (int i = 0; i < dataSource.Columns.Count; i++)
                        {
                            sqlbulkcopy.ColumnMappings.Add(dataSource.Columns[i].ColumnName, dataSource.Columns[i].ColumnName);
                        }
                        sqlbulkcopy.WriteToServer(dataSource);
                        tran.Commit();
                    }
                    catch (Exception ex) 
                    {
                        msg = ex.Message;
                        tran.Rollback();
                    }
                }
            }
        }
    }
}

    dt有个RID,是因为外层我的查询字符串处理了根据RID处理了分页,所以这里插入前处理下这个列,下面的设置列映射很好用,如果不映射的话默认是一列一列对齐插入的,遇到表字段非常多的情况,写起来很麻烦。

    言归正传,“从 bcp 客户端收到一个对 colid 7 无效的列长度”,这个错误是怎么来的呢?看现象是DataTable和表之间数据长度不一致,我的DataTable如下:

    colid 7,我原本一位是d_branch_no字段,因为从0开始数的话,索引为7的刚好是d_branch_no,所以分析是这个列没有值导致报错。后面发现不是。

    colid 7是指DataTable的第7列,从1开始数!初看branch_no是没有问题的,我们数据库这个字段在我现在要用的表里就是6位,那为什么报错呢?

    眼睛看了好久看不出来,把查DataTable的语句在查询分析器中通过INSERT INTO ... SELECT ... FROM 的形式执行是正常的,这可就难到我了。这种问题一般就是某个细节没注意到,和预期不一致导致问题产生。

    果然,我想起我们系统里的“历史债务”,很多表的字段用的char类型,char类型当位数不足时自动用空格补齐内容。

    比如field字段设计的是char(6),如果field存进去的是00,那么这个字段在数据库的值是 “00    ”,而非 “00”,所以查询的时候如果没有考虑空格,那么就会出现和预期不一致的现象,一些奇怪的bug由此而生!

    在前面的笔记中提到过,数据库字段设计为char类型是历史债务,现在不适合改类型,影响面太广。因此这里的做法是查询的时候使用rtrim把空格去掉,这样DataTable没有空格后,数据就可以正常插入了。

 

    小结:空格防不胜防,只能自己多加小心了。

 

posted @ 2024-09-03 11:52  顾星河  阅读(82)  评论(0编辑  收藏  举报