批量插入、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 2008r2 向带有索引的表里大批量插入数据