批量插入带有可选的文本限定符

时间:2009-09-04 10:52:55

标签: c# sql sql-server csv bulkinsert

我使用批量插入将csv导入db。 它是逗号分隔的csv文件。所有字段都没有文本限定符。

但有些字段可能会将逗号作为数据的一部分。 例如,ADDRESS字段值。这些值用双引号括起来。 这些双引号仅在字段值中包含逗号时出现,否则值不会被双引号括起来。 因此,在某些行中,ADDRESS值用双引号括起来,但在其他行中它们不是。 有没有办法在批量插入命令中指定text-qualifier?

我尝试使用格式文件选项批量插入。

BULK INSERT Test_Imported FROM 'C:\test.csv' 
WITH (FIRSTROW=0,FIELDTERMINATOR = ',',ROWTERMINATOR = '\n',FORMATFILE = 'C:\test.Fmt')

但我无法在格式文件中将双引号作为可选文本限定符提及。

PS: 这个函数实际上是更大模块的一部分,用c#编写。 从c#调用bulk insert命令。

csv文件来自另一个自动化系统的电子邮件。我无法控制格式 csv文件。大约有150列。 平均每个csv文件中有12000行。 忘了spcify DB。它是SQL server 2005。

6 个答案:

答案 0 :(得分:4)

批量插入语句真的很糟糕,因为它不处理可选的限定符。

TextFieldParser 类可以帮助我们清理文件( Microsoft.VisualBasic.FileIO.TextFieldParser

我已经粘贴了一个函数,该函数使用 TextFieldParser 类来清理分隔文件,以便您可以在批量插入语句中使用它。

String newDel = CleanDelimitedFile("c:\temp.csv",new String[] {","},"\t,\t");

这是一个清理分隔文件的函数。

    /// <summary>
    /// This function opens a delimited file and cleans up any string quantifiers
    /// </summary>
    /// <param name="FileFullPath">Full path of the delimited string</param>
    /// <param name="CurrentDelimiter">What string / character the file uses as the delimiter</param>
    /// <param name="NewDelimiter">What new delimiter string to use</param>
    /// <returns>Returns String representation of the new delimited file</returns>
    private static String CleanDelimitedFile(String FileFullPath, String[] CurrentDelimiter, String NewDelimiter) {

        //-- if the file exists stream it to host
        if (System.IO.File.Exists( FileFullPath )) {
            Microsoft.VisualBasic.FileIO.TextFieldParser cvsParser = null;
            System.Text.StringBuilder parseResults = new System.Text.StringBuilder();
            try {
                // new parser
                cvsParser = new Microsoft.VisualBasic.FileIO.TextFieldParser(FileFullPath);
                // delimited file has certain fields enclosed in quotes
                cvsParser.HasFieldsEnclosedInQuotes = true;
                // the current delimiter
                cvsParser.Delimiters = CurrentDelimiter;
                // iterate through all the lines of the file
                Boolean FirstLine = true;
                while (!cvsParser.EndOfData ) {
                    if (FirstLine) {
                        FirstLine = false;
                    }
                    else {
                      parseResults.Append("\n");  
                    }
                    Boolean FirstField = true;
                    // iterate through each field
                    foreach (String item in cvsParser.ReadFields()) {
                        if (FirstField) {
                            parseResults.Append(item);
                            FirstField = false;
                        } 
                        else {
                            parseResults.Append(NewDelimiter + item);
                        }
                    }

                }
                return parseResults.ToString();
            }
            finally {
                if (cvsParser != null) {
                    cvsParser.Close();
                    cvsParser.Dispose();
                }
            }
        }
        return String.Empty;
    }

答案 1 :(得分:3)

不幸的是,您必须预先处理文件以使其保持一致。 SQL批量操作将字符串拆分为字段分隔符。

一些选项:

  • 在c#中处理以更改逗号未被引号包围的逗号(|)
  • 将文件分解为2:“和非”文件。仅当相同字段具有“
  • 时,此方法才有效

你说你无法控制格式,但你拥有的东西是无法使用的......

答案 2 :(得分:1)

可悲的是,SQL 2005和2008导入XLS文件比CSV文件更顺畅。我从来都不是反微软,但除非所有ANSI标准的数据库管理都发生了巨大的变化,并且文本限定符的概念被放弃了(我非常怀疑),那么这可能是MS的专有举措。 SQL 2000处理文本限定符很好(不确定BULK命令,因为我一直只使用导入向导)。想象一下,当我们迁移到2005年时,我不得不将我的所有进程重新编译为不导入平面文件,而是导入XLS。我只花了16个小时(是的,两个工作日)来得出这个结论,我实际上在那个星期失去了睡眠,因为我因为不允许使用文本限定符而对MS感到非常沮丧(我甚至进入我的老板办公室道歉把这么多时间花在应该是10分钟的任务上。具有讽刺意味的是,您不能告诉Excel导出任何包含双引号文本限定符(或几乎任何其他软件导出器)的内容。 GRRRRRR。

所有这一切中最令人沮丧的部分是SQL 2005导入向导有一个定义文本限定符的地方!

...我敢说在这次经历之后我开始理解所有的反M $修辞!

答案 3 :(得分:0)

非常好的解释文章

  1. 如何创建格式文件

  2. 逐步解释了每一栏的含义

  3. SQL版,如何使用。

  4. 请参阅此链接Bulk insert with text qualifier in sql server

答案 4 :(得分:0)

我知道这是一个老问题,但我有一个TSQL方法来处理间歇引用分隔符。它可能不是很漂亮,但它可能会帮助那些在那里找到方法的人:

  1. 导入文本文件,每行包含一列 - 一个字段。
  2. 使用下面的更新语句将引号之间的逗号更改为某些可识别的字符串,在本例中为*&*
  3. 使用其他更新语句删除所有引号。
  4. 使用bcp将数据导出到新的CSV文件中。
  5. 使用新CSV文件中的所有字段执行批量导入原始表格:现在没有引号,而现场逗号则是&amp; ,所以一个简单的逗号分隔导入将起作用。
  6. 使用其他更新语句将&amp; 更改回逗号。
  7. UPDATE InitialTable SET BulkColumn = REPLACE(BulkColumn, SubString(BulkColumn, CHARINDEX('"', BulkColumn, 0), CHARINDEX('"', BulkColumn, CHARINDEX('"', BulkColumn, 0) + 1) - CHARINDEX('"', BulkColumn, 0) + 1), REPLACE( SubString(BulkColumn, CHARINDEX('"', BulkColumn, 0), CHARINDEX('"', BulkColumn, CHARINDEX('"', BulkColumn, 0) + 1) - CHARINDEX('"', BulkColumn, 0) + 1), ',', '*&*')) WHERE BulkColumn LIKE '%"%'

答案 5 :(得分:0)

对我有用的是改变

ROWTERMINATOR = '\n'

收件人:

ROWTERMINATOR = '0x0a'