批量插入、SQL Server 2000、unix 换行符

Posted

技术标签:

【中文标题】批量插入、SQL Server 2000、unix 换行符【英文标题】:Bulk insert, SQL Server 2000, unix linebreaks 【发布时间】:2010-10-03 13:11:25 【问题描述】:

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

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

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

【问题讨论】:

【参考方案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 的内容时会发生什么?

【讨论】:

以上是关于批量插入、SQL Server 2000、unix 换行符的主要内容,如果未能解决你的问题,请参考以下文章

sql server有批量插入和批量更新的sql语句吗

SQL Server 批量插入是事务性的吗?

sql server 2008r2 向带有索引的表里大批量插入数据

sql server返回插入记录的ID(多条记录)

如何写sqlserver2000存储过程?用于批量录入数据,求解

SQL Server / MySQL / Access - 以低效的方式加速插入许多行