映射列

时间:2016-09-15 20:12:49

标签: c# linq sqlbulkcopy

我正在尝试通过映射列名来从一个表批量复制到另一个表,因为源和目标可能始终没有相同的列。

源可以有8列,目标可以有10 ..我需要映射列和批量复制。

尝试了下面的代码......没有工作......忘记错误:给定的ColumnName' moduleid'与数据源中的任何列都不匹配。

来源:existingtablecolumnsPresent有[收集时间],[logtime],[moduleid],[node],[reason],[time],[timestamp],[usecaseid]

目的地:dataTable.Columns有[Node],[Time],[Reason],[Moduleid],[Usecaseid]

请告知

 public static void BatchBulkCopy(DataTable dataTable, string DestinationTbl,  List<string> columnMapping,string filename)
    {
        var program = new Program();
        // Get the DataTable 
        DataTable dtInsertRows = dataTable;

        using (SqlBulkCopy sbc = new SqlBulkCopy(program.connectionStr.ToString()))
        {


            try { 
            sbc.DestinationTableName = DestinationTbl.ToLower();

            string sourceTableQuery = "Select top 1 * from " + "[" + dataTable.TableName + "]";
            DataTable dtSource = SqlHelper.ExecuteDataset(program.connectionStr.ToString(), CommandType.Text, sourceTableQuery).Tables[0];

            for (int i = 0; i < dataTable.Columns.Count; i++)
            {    //check if destination Column Exists in Source table
                if (dtSource.Columns.Cast<DataColumn>().Select(a => "[" + a.ColumnName.ToLower() + "]").Contains(dataTable.Columns[i].ToString().ToLower()))//contain method is not case sensitive
                {
                        List<string> existingtablecolumnsPresent = dtSource.Columns.Cast<DataColumn>().Select(a => "[" + a.ColumnName.ToLower() + "]").Distinct().OrderBy(t => t).ToList();

                        int sourceColumnIndex = existingtablecolumnsPresent.IndexOf(dataTable.Columns[i].ToString().ToLower());//Once column matched get its index
                    sbc.ColumnMappings.Add(dtSource.Columns[sourceColumnIndex].ToString(), dtSource.Columns[sourceColumnIndex].ToString());//give coluns name of source table rather then destination table so that it would avoid case sensitivity
                }

            }
            sbc.WriteToServer(dtInsertRows);
            sbc.Close();
        }

        catch (Exception ex)
        {
            Log.WriteLog("BatchBulkCopy" + " - " + filename, dataTable.TableName, ex.Message.ToString());

            // To move a file or folder to a new location:
            //if (File.Exists(program.sourceFile + filename))
            //    System.IO.File.Move(program.sourceFile + filename, program.failedfiles + filename);

        }

2 个答案:

答案 0 :(得分:1)

根据要求(创建一个包含要插入其中的列的DataTable - 将其他列保留。请确保您遗漏的任何列在表中标记为NULL或具有DEFAULT VALUE约束(我无法显示)你怎么做,除非你告诉我你的表;)

 //This first method is psuedoCode to explain how to create your datatable. You need to do it in the way that makes sense for you.
 public DataTable createDataTable(){
    List<string> excludedColumns = new List<string>();
    excludedColumns.Add("FieldToExclude");
    //...
    DataTable dt = new DataTable();
    foreach(string col in getColumns(myTable)){
         if(!excludedColumns.Contains(name)){
         DataColumn dC = new DataColumn(name,type);
         DataTable.Add(dC);
     }
     return dt;
}


 public List<string> getColumns(string tableName)
    {
        List<string> ret = new List<string>();
        using (SqlConnection conn = getConn())
        {
            conn.Open();
            using (SqlCommand com = conn.CreateCommand())
            {
                com.CommandText = "select column_Name from information_schema.COLUMNS where table_name = @tab";
                com.Parameters.AddWithValue("@tab", tableName);
                SqlDataReader read = com.ExecuteReader();
                While(read.Read()){
                ret.Add(Convert.ToString(read[0]);
            }
            conn.Close();
        }
        return ret;
    }
 //Now, you have a DataTable that has all the columns you want to insert. Map them yourself in code by adding to the appropriate column in your datatable.
 public bool isCopyInProgess = false;//not necessary - just part of my code
    public  void saveDataTable(string tableName, DataTable table)
    {
        using (SqlConnection conn = getConn())
        {
            conn.Open();
            using (var bulkCopy = new SqlBulkCopy(conn))//, SqlBulkCopyOptions.KeepIdentity))//un-comment if you want to use your own identity column
            {
                // my DataTable column names match my SQL Column names, so I simply made this loop. However if your column names don't match, just pass in which datatable name matches the SQL column name in Column Mappings
                foreach (DataColumn col in table.Columns)
                {
                    //Console.WriteLine("mapping " + col.ColumnName+" ("+does_Column_Exist(col.ColumnName,"Item").ToString()+")");
                    bulkCopy.ColumnMappings.Add(col.ColumnName, "["+col.ColumnName+"]");
                   // Console.WriteLine("ok\n");
                }
                bulkCopy.BulkCopyTimeout = 8000;
                bulkCopy.DestinationTableName = tableName;
                bulkCopy.BatchSize = 10000;
                bulkCopy.EnableStreaming = true;
                //bulkCopy.SqlRowsCopied += BulkCopy_SqlRowsCopied;
                //bulkCopy.NotifyAfter = 10000;
                isCopyInProgess = true;
               bulkCopy.WriteToServer(table);
            }
            conn.Close();
        }
    }

另外,使用它作为你的bolumn检查器:

 public bool does_Column_Exist(string colName,string tableName)
    {
        bool ret = false;
        using (SqlConnection conn = getConn())
        {
            conn.Open();
            using (SqlCommand com = conn.CreateCommand())
            {
                com.CommandText = "select count(*) from information_schema.COLUMNS where column_name = @col and table_name = @tab";
                com.Parameters.AddWithValue("@tab", tableName);
                com.Parameters.AddWithValue("@col", colName);
                ret = Convert.ToInt32(com.ExecuteScalar()) == 0 ? false : true; 
            }
            conn.Close();
        }
        return ret;
    }

答案 1 :(得分:0)

你需要C#的具体原因是什么?似乎阻力最小的路径是使用SQL来完成这项工作。

INSERT INTO table2
(column_name(s))
SELECT column_name(s)
FROM table1;