具有不同排序规则的SqlBulkCopy

时间:2010-12-13 16:54:42

标签: .net sql-server sqlbulkcopy

我需要将数据从一个数据库迁移到另一个数据库。我选择使用SqlBulkCopy,但是有问题,因为源数据库的排序规则与目标不同,所以,我有一个例外:

System.InvalidOperationException: The locale id '1049' of the source column 'Id' and the locale id '1033' of the destination column 'Id' do not match.
   at System.Data.SqlClient.SqlBulkCopy.AnalyzeTargetAndCreateUpdateBulkCommand(BulkCopySimpleResultSet internalResults)
   at System.Data.SqlClient.SqlBulkCopy.WriteToServerInternal()
   at System.Data.SqlClient.SqlBulkCopy.WriteRowSourceToServer(Int32 columnCount)
   at System.Data.SqlClient.SqlBulkCopy.WriteToServer(IDataReader reader)
   at MigrateToNormalized.DirectMapCommand.Migrate(SqlConnection source, SqlConnection destination, SqlTransaction transaction) in D:\Projects\APS\DTE\MigrateTo
Normalized\MigrateToNormalized\MigrateToNormalized\DirectMapCommand.cs:line 53
   at MigrateToNormalized.Program.Main(String[] args) in D:\Projects\APS\DTE\MigrateToNormalized\MigrateToNormalized\MigrateToNormalized\Program.cs:line 32

任何人都可以告诉我,如何在不直接使用SQL查询中的COLLATE语句的情况下解决此问题?是否有一些简单的方法来更改源数据库中所有列的排序规则?

4 个答案:

答案 0 :(得分:3)

当我们使用SqlBulkCopy时,有时会出现错误,这是使用SqlBulkCopy时映射列的最佳方法。

我的首要代码:

SqlConnectionStringBuilder cb = new SqlConnectionStringBuilder("Data Source=ServerName;User Id=userid;Password=****;Initial Catalog=Deepak; Pooling=true; Max pool size=200; Min pool size=0");

SqlConnection con = new SqlConnection(cb.ConnectionString);

        SqlCommand cmd = new SqlCommand("select Name,Class,Section,RollNo from Student", con);

        con.Open();

        SqlDataReader rdr = cmd.ExecuteReader();

        SqlBulkCopy sbc = new SqlBulkCopy("Data Source=DestinationServer;User Id=destinationserveruserid;Password=******;Initial Catalog=DeepakTransfer; Pooling=true; Max pool size=200; Min pool size=0");

        sbc.DestinationTableName = "StudentTrans";


        sbc.WriteToServer(rdr);


        sbc.Close();
        rdr.Close();
        con.Close();

守则给我的错误是: 源列“RollNo”的区域设置ID“0”和目标列“Section”的区域设置ID“1033”不匹配。

现在,在列映射后,我的代码正在成功运行。

我的修改代码是:

SqlConnectionStringBuilder cb = new SqlConnectionStringBuilder("Data Source=ServerName;User Id=userid;Password=****;Initial Catalog=Deepak;");

        SqlConnection con = new SqlConnection(cb.ConnectionString);

        SqlCommand cmd = new SqlCommand("select Name,Class,Section,RollNo from Student", con);

        con.Open();

        SqlDataReader rdr = cmd.ExecuteReader();


        SqlBulkCopy sbc = new SqlBulkCopy("Data Source=DestinationServer;User Id=destinationserveruserid;Password=******;Initial Catalog=DeepakTransfer;");

        sbc.DestinationTableName = "StudentTrans";

        sbc.ColumnMappings.Add("Name", "Name");
        sbc.ColumnMappings.Add("Class", "Class");
        sbc.ColumnMappings.Add("Section", "Section");
        sbc.ColumnMappings.Add("RollNo", "RollNo");

        sbc.WriteToServer(rdr);
        sbc.Close();
        rdr.Close();
        con.Close();

此代码正在成功运行。

试试这个并享受。

答案 1 :(得分:2)

您可以选择具有不同排序规则的列:

SELECT Foo COLLATE SQL_Latin1_General_CP1_CI_AS AS Bar FROM Baz

这会将列Foo的排序规则转换为新的排序规则。在上面的示例中, Foo 列已转换为排序规则SQL_Latin1_General_CP1_CI_AS,并在查询中命名为

然后,您需要为bulkcopy命令的 new 列添加列映射:

using (var bulkCopy = new SqlBulkCopy(connection))
{
    bulkCopy.DestinationTableName = "FooBars";
    bulkCopy.ColumnMappings.Add("Bar", "FooBar"); 
    bulkCopy.WriteToServer(reader);
}

答案 2 :(得分:1)

简单的添加列映射对我来说不起作用。我已经通过SqlBulkCopy和DataTable实现了插件 - 这个工作正常。

private void BulkCopyTable(string sourceConnection, string targetConnection, Table sTable, Table tTable)
    {
        using (SqlConnection sourceConn = new SqlConnection(sourceConnection))
        {
            if (cbFixStructure.Checked)
                CheckAndRecreateTarget(targetConnection, sTable, tTable);

            string selectSql = "SELECT * FROM " + sTable.Schema + ".[" + sTable.Name + "]";

            string selectCntSql = "SELECT COUNT(*) FROM " + sTable.Schema + ".[" + sTable.Name + "] WITH(NOLOCK)";
            using (SqlCommand selectCmd = new SqlCommand(selectSql, sourceConn))
            {
                selectCmd.CommandTimeout = 60 * 100 * 1000;
                sourceConn.Open();
                Int64 totalCount = 0;
                using (SqlCommand cntCommand = new SqlCommand(selectCntSql, sourceConn))
                {
                    cntCommand.CommandTimeout = 60 * 100 * 1000;
                    totalCount = Convert.ToInt64(cntCommand.ExecuteScalar());
                }

                DataTable dtBuffer = new DataTable();
                var columns = sTable.Columns.Cast<Column>().Where(p => p.Computed == false).ToList();
                foreach (var clm in columns)
                {

                    var sdt = clm.DataType.SqlDataType;
                    if (sdt == SqlDataType.UserDefinedDataType)
                    {
                        var lst = Enum.GetValues(typeof(SqlDataType)).Cast<SqlDataType>();
                        sdt = lst.Where(p => p.ToString().ToLower() == TargetDataBase.UserDefinedDataTypes[clm.DataType.Name].SystemType.ToString()).First();
                    }


                    dtBuffer.Columns.Add(new DataColumn(clm.Name, GetClrType(sdt)));
                }
                using (SqlDataReader reader = selectCmd.ExecuteReader())
                {

                    using (SqlBulkCopy blkCopy = new SqlBulkCopy(targetConnection, SqlBulkCopyOptions.KeepIdentity))
                    {
                        blkCopy.BulkCopyTimeout = 60 * 100 * 1000;
                        blkCopy.DestinationTableName = sTable.Schema + ".[" + sTable.Name + "]";


                        foreach (var colmn in columns)
                        {
                            blkCopy.ColumnMappings.Add(colmn.Name, colmn.Name);
                        }


                        int bufferCountLengthMax = 500;
                        int rowCnt = 0;
                        int globalCounter = 0;
                        while (reader.Read())
                        {
                            var dataRow = dtBuffer.NewRow();
                            foreach (var clm in columns)
                            {
                                dataRow[clm.Name] = reader[clm.Name];
                            }
                            dtBuffer.Rows.Add(dataRow);
                            rowCnt++;
                            globalCounter++;
                            if (rowCnt >= bufferCountLengthMax)
                            {
                                dtBuffer.AcceptChanges();
                                blkCopy.WriteToServer(dtBuffer);
                                rowCnt = 0;
                                dtBuffer.Rows.Clear();
                                GC.Collect();
                                DoLogText(String.Format("Table \"{0}\" copied rows {1} out of {2}", sTable.Schema + ".[" + sTable.Name + "]", globalCounter, totalCount));
                            }
                        }
                        if (rowCnt > 0)
                        {
                            dtBuffer.AcceptChanges();
                            blkCopy.WriteToServer(dtBuffer);
                            rowCnt = 0;
                            dtBuffer.Rows.Clear();
                            GC.Collect();
                            DoLogText(String.Format("Table \"{0}\" copied rows {1} out of {2}", sTable.Schema + ".[" + sTable.Name + "]", globalCounter, totalCount));
                        }

                    }
                }
            }

        }
        DoLogText(String.Format("Table \"{0}\" done", sTable.Name));
    }

答案 3 :(得分:-1)

您可以更改用于sqlbulkcopy的表中列的排序规则。

例如

创建表T3 (     C1 int PRIMARY KEY,     C2 varchar(50)NULL,     C3 int NULL,     C4 int ); GO

ALTER TABLE T3      ALTER COLUMN C2 varchar(50)COLLATE Latin1_General_BIN