批量插入,SQL Server 2000,Unix换行符

36

我正在尝试使用Unix换行符将一个.csv文件插入到数据库中。我运行的命令是:

BULK INSERT table_name
FROM 'C:\file.csv' 
WITH 
( 
    FIELDTERMINATOR = ',', 
    ROWTERMINATOR = '\n' 
) 
如果我将文件转换为Windows格式,则可以加载,但如果可以避免这个额外的步骤,我不想这样做。 有什么建议吗?
8个回答

102

我觉得有必要做出贡献,因为我也遇到了同样的问题,我每天至少需要阅读两个来自SAP的UNIX文件。因此,我不想使用unix2dos,而是需要通过编程自动化地减少手动干预。

如前所述,Char(10)可在sql语句中使用。我不想使用sql语句,所以我使用了''''+Char(10)+'''',但由于某种原因,这无法编译。

非常顺利的解决方法是:使用 (ROWTERMINATOR = '0x0a')

通过十六进制解决了问题!


不幸的是,这并没有对我的以LF结尾的Unix文件起作用,但动态SQL解决方案确实起了作用! - samaspin
是的,Randy,这非常有帮助!我记得有一种方法可以指定十六进制字符,当然 A = 十六进制 10,但我记不起语法了。非常感谢你(我都快疯了)。 - Thomas Fonseca
这对我有用,但是建议在许多其他地方使用ROWTERMINATOR = '''+CHAR(10)+'''并不适用。我使用的是SQL Server 12.0.2000.8版本。 - battey

15

感谢所有回答过我的人,但我已经找到了我想要的解决方案。

如果您告诉 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部分中无法评估任何表达式。

上面的操作是创建一个命令字符串并执行它。这样巧妙地规避了创建额外文件或进行额外步骤的需要。


5

我确认语法

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

当与EXEC命令一起使用时,此功能可正常工作。

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

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

3

这个问题有点复杂!当你告诉SQL Server ROWTERMINATOR='\n'时,它会将其解释为Windows下的默认行终止符,实际上是"\r\n"(使用C / C ++表示法)。如果你的行终止符只是"\n",则必须使用上面显示的动态SQL。我刚刚花了大约一个小时来弄清楚为什么在BULK INSERT中使用 \n 时它并不真正意味着 \n!


1

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

虽然您已经表示不希望这样做,但另一种选择是使用unix2dos对文件进行预处理,使其具有'\r\n'换行符。

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


它确实可以,因此能够使用bcp文件来指定输入格式。 - ConcernedOfTunbridgeWells

0

在我看来,有两条通用途径可供选择:一是使用 SQL 脚本中的某种替代方法来读取 CSV,二是使用众多可行的方式之一(如 bcp、unix2dos),事先将 CSV 转换好(如果只需做这件事一次,你甚至可以使用代码编辑器为其修复文件)。

但这样就需要额外一个步骤!

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

好吧,好吧。第四种情况有点牵强附会。虽然这种情况在电子邮件中会发生,但那是另一回事。


0
我认为“ROWTERMINATOR ='\n'”就可以了。我建议在显示“隐藏字符”的工具中打开文件,以确保该行被终止的方式与您想象的一样。我通常使用Notepad++来处理这种情况。

1
是的,你可能认为它会起作用。大多数人也是这么想的。但事实并非如此。\n会自动替换为\r\n,因此需要其他解决方法才能获得单独的LF。 - underscore_d

0

问题就在这里。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 代码时,它没有用 LF 字符替换 char(10)(因为它已经被放在单引号中)。或者也许它被解释为:
(ROWTERMINATOR =
     )

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

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接