【问题标题】:Import CSV with missing columns into MS SQL Server table将缺少列的 CSV 导入 MS SQL Server 表
【发布时间】:2022-01-04 18:43:43
【问题描述】:

假设我有一个这样的 csv 文件:

field1 field3
0      1
1      2

对应的表格如下:

field1 field2 field3
null   null   null
...    ...    ...

假设所有字段都可以为空,我如何将 csv 文件导入表中?我知道我可以 BULK INSERT 使用格式化程序,但我无法通过 bcp 生成格式化程序,因为与本地 SQL 服务器的连接失败(奇怪!)有没有更好的方法来解决这个问题?

【问题讨论】:

  • 批量插入临时表,然后将INSERT 插入生产表。
  • 因为与本地 SQL 服务器的连接失败(奇怪!) 猜猜你需要先解决这个问题,因为如果无法连接,则无法导入任何内容。

标签: sql asp.net sql-server asp.net-core


【解决方案1】:

将 csv/txt 分隔的文件移动到 SQL Server 表中时可能会很棘手。我让用户弄乱了列或列太多等。我的解决方案是首先使用流阅读器读取文件,然后将标题行添加到数组中,将数据本身放入自己的数组中。然后我循环遍历标题数组并将每个值添加到空 DataTable 中的列中。 所以现在我有一个包含标题名称(代表 SQL Server 中的列名)的数据表和另一个包含实际数据的数据表。 然后查询 SQL server Table 以获取 Column 名称的字典列表:

        Dictionary<int, string> SQLTableColNamesDict = new Dictionary<int, string>();

        string Command = " SELECT COLUMN_NAME, ORDINAL_POSITION FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_NAME = 'table name' ";
        using (SqlConnection Connection = new SqlConnection(sqlconnectionstring))
        {
            Connection.Open();
            using (SqlCommand cmd = new SqlCommand(Command, Connection))
            {
                using (SqlDataReader reader = cmd.ExecuteReader())
                {
                    while (reader.Read())
                    {
                        SQLTableColNamesDict.Add((int)reader[1], (string)reader[0].ToString().ToUpper());
                    }
                }
            }
        }

然后循环遍历 header 数组,看看字典列表是否匹配 header 值,如果有匹配则使用 Bulk Copy 映射列。

             using (SqlBulkCopy bulkCopy = new SqlBulkCopy(sqlconnectionstring))
        {
            bulkCopy.DestinationTableName = SQLdestinationTable;

            bulkCopy.BatchSize = dtWithColNames.Rows.Count;

            foreach (string columnFromFile in firstRowHeaderFromFileArray)
            {



                string DesintationOrdinalPostion = "";
                string DesintationColName = "";

                if (SQLTableColNamesDict.ContainsValue(columnFromFile.ToUpper()))
                {
                    DesintationOrdinalPostion = SQLTableColNamesDict.First(item => item.Value == columnFromFile.ToUpper()).Key.ToString();

                    DesintationColName = SQLTableColNamesDict.First(item => item.Value == columnFromFile.ToUpper()).Value.ToString();

                }


                if (DesintationOrdinalPostion != "")
                // if (colFound != null)
                {
                    SqlBulkCopyColumnMapping col = new SqlBulkCopyColumnMapping();


                    // col.SourceColumn = columnFromFile;

                    col.SourceColumn = DesintationColName;

                    col.DestinationOrdinal = Convert.ToInt32(DesintationOrdinalPostion);
                    col.DestinationColumn = columnFromFile.ToUpper();


                    bulkCopy.ColumnMappings.Add(col);


                }

            }

然后最后进行批量复制

                 int recordCount = 0;
            recordCount = dtWithColNames.Rows.Count;

            // Write from the source to the destination.
            try
            {
                bulkCopy.WriteToServer(dtWithColNames);



            }
            catch (Exception error)
            {

            }
            finally
            {

                bulkCopy.Close();

            }

这应该允许传输工作,即使 csv 文件可能带有额外的列格式错误并且只接受与您的 SQL 表匹配的有效列。

【讨论】:

    【解决方案2】:

    您可以创建一个 staging 表,其中仅包含数据 csv 文件中的列,然后使用 BCP 将数据加载到该表中。之后使用INSERT INTO ...SELECT ..FROM 将数据加载到目标表。 请参阅此answer 了解更多详情。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2021-02-04
      • 2015-01-27
      • 1970-01-01
      • 1970-01-01
      • 2014-03-12
      • 1970-01-01
      • 2012-06-16
      相关资源
      最近更新 更多