【问题标题】:Bulk insert, SQL Server 2000, unix linebreaks批量插入、SQL Server 2000、unix 换行符
【发布时间】:2026-01-03 08:30:01
【问题描述】:

我正在尝试将 .csv 文件插入到带有 unix 换行符的数据库中。我正在运行的命令是:

BULK INSERT table_name
FROM 'C:\file.csv' 
WITH 
( 
    FIELDTERMINATOR = ',', 
    ROWTERMINATOR = '\n' 
) 

如果我将文件转换为 Windows 格式,则加载工作正常,但如果可以避免,我不想执行此额外步骤。有什么想法吗?

【问题讨论】:

    标签: sql sql-server bulkinsert


    【解决方案1】:

    我觉得有必要做出贡献,因为我遇到了同样的问题,而且我每天至少需要从 SAP 读取 2 个 UNIX 文件几次。因此,我不需要使用 unix2dos,而是需要人工干预更少、通过编程更自动化的东西。

    如上所述,Char(10) 在 sql 字符串中工作。我不想使用 sql 字符串,所以我使用了 ''''+Char(10)+'''',但是由于某种原因,它没有编译。

    非常巧妙的是:with (ROWTERMINATOR = '0x0a')

    用十六进制解决问题!

    希望这对某人有所帮助。

    【讨论】:

    • 感谢@Randy J。更改了已接受的答案,因为这是一个更好的解决方案。
    • 不幸的是,这不适用于我的以 LF 终止的 unix 文件,但动态 SQL 解决方案确实有效!
    • 谢谢!在我找到这篇文章之前,我只浪费了大约 10 分钟的时间来搞定 rowterminator。可能会更糟......
    • 是的,兰迪帮了大忙!我记得有一种方法可以指定十六进制字符,当然 A = hex 10 但我不记得语法了。非常感谢(我快疯了)。
    • 谢谢!!你每个月为我节省了两个小时!
    【解决方案2】:

    感谢所有回答的人,但我找到了我喜欢的解决方案。

    当您告诉 SQL Server ROWTERMINATOR='\n' 时,它会将其解释为 Windows 下的默认行终止符,实际上是“\r\n”(使用 C/C++ 表示法)。如果您的行终止符真的只是“\n”,您将不得不使用下面显示的动态 SQL。

    DECLARE @bulk_cmd varchar(1000)
    SET @bulk_cmd = 'BULK INSERT table_name
    FROM ''C:\file.csv''
    WITH (FIELDTERMINATOR = '','', ROWTERMINATOR = '''+CHAR(10)+''')'
    EXEC (@bulk_cmd)
    

    为什么你不能说 BULK INSERT ...(ROWTERMINATOR = CHAR(10)) 超出了我的范围。看起来您无法评估命令的 WITH 部分中的任何表达式。

    上面所做的是创建一个命令字符串并执行它。巧妙地回避了创建额外文件或执行额外步骤的需要。

    【讨论】:

      【解决方案3】:

      我确认语法

      ROWTERMINATOR = '''+CHAR(10)+'''
      

      与 EXEC 命令一起使用时有效。

      如果您有多个 ROWTERMINATOR 字符(例如管道和 unix 换行符),则其语法为:

      ROWTERMINATOR = '''+CHAR(124)+''+CHAR(10)+'''
      

      【讨论】:

        【解决方案4】:

        比这要复杂一点!当您告诉 SQL Server ROWTERMINATOR='\n' 时,它会将其解释为 Windows 下的默认行终止符,实际上是“\r\n”(使用 C/C++ 表示法)。如果您的行终止符实际上只是“\n”,您将不得不使用上面显示的动态 SQL。我刚刚花了一个小时的大部分时间弄清楚为什么 \n 在与 BULK INSERT 一起使用时并不真正意味着 \n!

        【讨论】:

          【解决方案5】:

          一种选择是使用bcp,并设置一个以'\n' 作为换行符的控制文件。

          尽管您已表示不希望这样做,但另一种选择是使用 unix2dos 将文件预处理为带有 '\r\n' 换行符的文件。

          最后,您可以在BULK INSERT 上使用FORMATFILE 选项。这将使用 bcp 控制文件来指定导入格式。

          【讨论】:

          • 确实如此,因此它能够使用 bcp 文件来指定输入格式。
          【解决方案6】:

          在我看来,可以采用两种通用途径:在 SQL 脚本中读取 CSV 的另一种方法,或者使用您可以执行的多种方法中的任何一种预先转换 CSV(bcp、unix2dos,如果它是曾经的王者,您甚至可以使用代码编辑器为您修复文件)。

          但是你必须有一个额外的步骤!

          如果此 SQL 是从某个程序启动的,您可能希望转换该程序中的行尾。在这种情况下,您决定自己编写转换代码,以下是您需要注意的事项: 1. 行尾可能是\n 2. 或 \r\n 3. 甚至 \r (Mac!) 4. 很遗憾,可能有些行有\r\n,而另一些行有\n,除非您控制CSV 的来源,否则任何组合都是可能的

          好的,好的。可能性4是牵强附会的。它发生在电子邮件中,但那是另一回事了。

          【讨论】:

            【解决方案7】:

            我认为“ROWTERMINATOR = '\n'”会起作用。我建议在显示“隐藏字符”的工具中打开文件,以确保该行像您想象的那样被终止。我用记事本++来做这样的事情。

            【讨论】:

            • 是的,你会认为它会起作用。我们大多数人也是如此。但事实并非如此。 \n 会自动替换为 \r\n,因此需要其他解决方法来自行获取 LF。
            【解决方案8】:

            归结为这一点。 Unix 使用 LF (ctrl-J),MS-DOS/Windows 使用 CR/LF (ctrl-M/Ctrl-J)。

            当您在 Unix 上使用 '\n' 时,它会被转换为 LF 字符。在 MS-DOS/Windows 上,它被翻译成 CR/LF。当您的导入在 Unix 格式的文件上运行时,它只看到一个 LF。因此,首先通过 unix2dos 运行文件通常更容易。但正如你在最初的问题中所说,你不想这样做(我认为你不能这样做是有充分理由的)。

            你为什么不能这样做:

            (ROWTERMINATOR = CHAR(10))
            

            可能是因为在解析 SQL 代码时,它没有将 char(10) 替换为 LF 字符(因为它已经包含在单引号中)。或者也许它被解释为:

            (ROWTERMINATOR =
                 )
            

            当你回显@bulk_cmd 的内容时会发生什么?

            【讨论】: