【问题标题】:Exporting CSV to SQL in C# - how to offset the export by one column在 C# 中将 CSV 导出到 SQL - 如何将导出偏移一列
【发布时间】:2019-10-10 23:27:43
【问题描述】:

我正在使用 C# 解析 csv 文件并导出到 SQL Server 数据库表。数据库表的架构与 csv 文件的架构几乎相同,不同之处在于该表的第一列是主键标识列。

问题:数据库表的第2列,应该接收第1列csv 文件,实际上是接收 csv 文件的第二列。该代码假设数据库表的第一个 PK Identity 列是要从 CSV 文件写入的第一列。万一这令人困惑,假设 CSV 文件的第 1、2 和 3 列分别具有名为 Contoso1Contoso2Contoso3 的标题。数据库表的列 1 到 4 分别称为 IdContoso1Contoso2Contoso3。在导出过程中,Id 列正确地填充了身份 ID,但随后数据库表的 Contoso1 列填充了 CSV 文件的 Contoso2 列,并且被关闭一列继续对于所有 300 列。

这里是代码。我正在寻找一种使用此代码进行单列偏移的方法。如果可能的话,我想避免硬编码映射方案,因为有 300 多列。

using System;
using System.Data.SqlClient;
using System.Data;
using Microsoft.VisualBasic.FileIO;

namespace CSVTest
{
    class Program
    {
        static void Main(string[] args)
        {

            string csv_file_path = @"pathToCsvFile";
            DataTable csvData = GetDataTabletFromCSVFile(csv_file_path);
            Console.WriteLine("Rows count:" + csvData.Rows.Count);
            InsertDataIntoSQLServerUsingSQLBulkCopy(csvData);
        }



        private static DataTable GetDataTabletFromCSVFile(string csv_file_path)
        {
            DataTable csvData = new DataTable();
            try
            {
                using (TextFieldParser csvReader = new TextFieldParser(csv_file_path))
                {
                    csvReader.SetDelimiters(new string[] { "," });
                    csvReader.HasFieldsEnclosedInQuotes = true;
                    string[] colFields = csvReader.ReadFields();
                    foreach (string column in colFields)
                    {
                        DataColumn datecolumn = new DataColumn(column);
                        datecolumn.AllowDBNull = true;
                        csvData.Columns.Add(datecolumn);
                    }
                    while (!csvReader.EndOfData)
                    {
                        string[] fieldData = csvReader.ReadFields();
                        //Making empty value as null
                        for (int i = 0; i < fieldData.Length; i++)
                        {
                            if (fieldData[i] == "")
                            {
                                fieldData[i] = null;
                            }
                        }
                        csvData.Rows.Add(fieldData);
                    }
                }
            }
            catch (Exception ex)
            {
                return null;
            }
            return csvData;
        }


        static void InsertDataIntoSQLServerUsingSQLBulkCopy(DataTable csvFileData)
        {
            using (SqlConnection dbConnection = new SqlConnection("Data Source=localhost;Initial Catalog=Database_Name;Integrated Security=SSPI;"))
            {
                dbConnection.Open();
                using (SqlBulkCopy s = new SqlBulkCopy(dbConnection))
                {
                    s.DestinationTableName = "TableName";
                    //foreach (var column in csvFileData.Columns)
                        //s.ColumnMappings.Add(column.ToString(), column.ToString());
                    s.WriteToServer(csvFileData);
                }
            }
        }
    }
}

【问题讨论】:

  • 只是为了论证 - 如果您的 csv 有一个虚拟列作为第一列,即在您的示例中,csv 列将是 Dummy、Contoso1、Contoso2 和 Contoso3,会发生什么?如果这解决了您的 SQL 导入问题,您可以有一个变量来保存 ID 列的数字位置(例如位置 2,计数从 0 开始),然后在 csv 中的该位置添加一个虚拟列。
  • 嗨 Rakesh - 这正是我一直在寻找的想法。所以我尝试在 csv 中插入一个虚拟列,是的,这确实可以解决 SQL 问题。现在,话虽如此,当我们进入生产环境时,我将无法控制 csv 文件(但是,它的架构不应该改变)。那么,您能否使用您所说的变量的代码示例来制定答案?如果有效,我当然会将其标记为答案。谢谢。
  • ID 列的位置是否提前知道,对于“特定”类型的文件,它是否总是相同的,即假设您有 3 个 csv(以及它们映射到的 3 个表) ) - 我们称它们为 A、B 和 C。对于文件 A,ID 列是位置 1,对于 B,它的位置是 4,对于 C,它的位置是 5,这些位置永远不会改变。这适用于您的情况吗?
  • 问题 2 - 您是否只需要在 csvs 中最多跳过一列。

标签: c# sql-server csv


【解决方案1】:

我假设-

一个。只需要跳过一列,但可以修改为添加多个要跳过的列

b.您提前知道要跳过的列的从零开始的索引。

除此之外,这里是您需要进行的 3 项修改。

  1. 添加变量以存储要跳过的索引
string csv_file_path = @"pathToCsvFile";
//Assuming just one index for the column number to skip - zero based counting. 
//perhaps read from the AppConfig
int columnIndexToSkip = 0;
DataTable csvData = GetDataTabletFromCSVFile(csv_file_path, columnIndexToSkip);
  1. 修改函数签名以采用额外的 int 参数
        private static DataTable GetDataTabletFromCSVFile(string csv_file_path, int columnIndexToSkip)
        {
  1. 在该索引处添加虚拟列
                            csvData.Rows.Add(fieldData);
                        }
                    }// end of while (!csvReader.EndOfData) loop

                    if (columnIndexToSkip >= 0)
                    {
                        csvData.Columns.Add("DUMMY").SetOrdinal(columnIndexToSkip);
                    }

我没有测试导入,但更新后的 csv 文件对我来说看起来不错。

【讨论】:

  • Rakesh - 谢谢,我现在就试试。两个假设 A.和 b。是正确的。我很快就会恢复。
  • Rakesh - 如果我将您的 columnIndexToSkip 变量从 2 更改为 0,我会得到想要的结果。也许我的解释令人困惑,但无论如何,使用 0 作品。如果您可以更新答案以将其从 2 更改为 0,我会将其标记为答案。谢谢!
  • Perfect - 2 只是我作为示例设置的一个值,它将由您要更新的 csv 和表决定。在您提供的示例中,id 是索引 0,这是您需要跳过的,因此 columnIndexToSkip 需要为 0。
猜你喜欢
  • 2018-04-03
  • 2016-05-27
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-02-21
  • 2010-10-22
相关资源
最近更新 更多