使用FIRSTROW参数的SQL批量插入会跳过以下行

时间:2009-06-22 21:03:56

标签: sql sql-server-2005 bulkinsert

我似乎无法弄清楚这是怎么回事。

以下是我尝试批量插入SQL Server 2005的文件示例:

***A NICE HEADER HERE***
0000001234|SSNV|00013893-03JUN09
0000005678|ABCD|00013893-03JUN09
0000009112|0000|00013893-03JUN09
0000009112|0000|00013893-03JUN09

这是我的批量插入声明:

BULK INSERT sometable
FROM 'E:\filefromabove.txt
WITH
(
FIRSTROW = 2,
FIELDTERMINATOR= '|',
ROWTERMINATOR = '\n'
)

但是,出于某种原因,我能得到的唯一输出是:

0000005678|ABCD|00013893-03JUN09
0000009112|0000|00013893-03JUN09
0000009112|0000|00013893-03JUN09

除非我完全删除标题并且不使用FIRSTROW参数,否则总是会跳过第一条记录。这怎么可能?

提前致谢!

6 个答案:

答案 0 :(得分:14)

我认为您不能使用BULK INSERT / BCP以不同的格式跳过行。

当我运行时:

TRUNCATE TABLE so1029384

BULK INSERT so1029384
FROM 'C:\Data\test\so1029384.txt'
WITH
(
--FIRSTROW = 2,
FIELDTERMINATOR= '|',
ROWTERMINATOR = '\n'
)

SELECT * FROM so1029384

我明白了:

col1                                               col2                                               col3
-------------------------------------------------- -------------------------------------------------- --------------------------------------------------
***A NICE HEADER HERE***
0000001234               SSNV                                               00013893-03JUN09
0000005678                                         ABCD                                               00013893-03JUN09
0000009112                                         0000                                               00013893-03JUN09
0000009112                                         0000                                               00013893-03JUN09

看起来需要'|'甚至在标题数据中,因为它读取到第一列 - 将换行符吞入第一列。显然,如果你包含一个字段终止符参数,它希望每行必须都有一个。

您可以使用预处理步骤去除行。另一种可能性是仅选择完整的行,然后处理它们(排除标题)。或者使用可以处理此问题的工具,例如SSIS。

答案 1 :(得分:8)

也许检查标题是否与实际数据行具有相同的行结尾(在ROWTERMINATOR中指定)?

更新:来自MSDN

  

不打算使用FIRSTROW属性   跳过列标题。跳绳   BULK不支持标头   INSERT语句。跳过行时,   SQL Server数据库引擎看起来   只在现场终结者,和   不验证中的数据   跳过的字段。

答案 2 :(得分:6)

我发现最简单的方法是将整行读入一列,然后使用XML解析数据。

IF (OBJECT_ID('tempdb..#data') IS NOT NULL) DROP TABLE #data
CREATE TABLE #data (data VARCHAR(MAX))

BULK INSERT #data FROM 'E:\filefromabove.txt' WITH (FIRSTROW = 2, ROWTERMINATOR = '\n')

IF (OBJECT_ID('tempdb..#dataXml') IS NOT NULL) DROP TABLE #dataXml
CREATE TABLE #dataXml (ID INT NOT NULL IDENTITY(1,1) PRIMARY KEY CLUSTERED, data XML)

INSERT #dataXml (data)
SELECT CAST('<r><d>' + REPLACE(data, '|', '</d><d>') + '</d></r>' AS XML)
FROM #data

SELECT  d.data.value('(/r//d)[1]', 'varchar(max)') AS col1,
        d.data.value('(/r//d)[2]', 'varchar(max)') AS col2,
        d.data.value('(/r//d)[3]', 'varchar(max)') AS col3
FROM #dataXml d

答案 3 :(得分:0)

您可以使用以下代码段

BULK INSERT TextData
FROM 'E:\filefromabove.txt'
WITH
(
FIRSTROW = 2,
FIELDTERMINATOR = '|',  --CSV field delimiter
ROWTERMINATOR = '\n',   --Use to shift the control to next row
ERRORFILE = 'E:\ErrorRows.csv',
TABLOCK
)

答案 4 :(得分:0)

要让SQL处理引号转义,其他所有操作都要这样做

BULK INSERT Test_CSV
FROM  'C:\MyCSV.csv' 
WITH (
 FORMAT='CSV'
 --FIRSTROW = 2,  --uncomment this if your CSV contains header, so start parsing at line 2
);

关于其他答案,这也是有价值的信息:

我一直在所有答案中看到这一点:ROWTERMINATOR = '\n'
\n表示LF,它是Linux风格的EOL

在Windows中,EOL由2个字符的CRLF组成,因此您需要ROWTERMINATOR = '\r\n'

enter image description here

enter image description here

答案 5 :(得分:-1)

鉴于BCP从非SQL数据源导入SQL Server后,一些数据可能会出现多少损坏,我建议先将所有BCP导入到某些临时表中。

例如

截断表Address_Import_tbl

BULK INSERT dbo.Address_Import_tbl 来自'E:\ external \ SomeDataSource \ Address.csv' WITH( FIELDTERMINATOR ='|',ROWTERMINATOR ='\ n',MAXERRORS = 10 )

确保Address_Import_tbl中的所有列都是nvarchar(),以使其尽可能不可知,并避免类型转换错误。

然后将所需的任何修复应用于Address_Import_tbl。比如删除不需要的标题。

然后运行INSERT SELECT查询,从Address_Import_tbl复制到Address_tbl,以及您需要的任何数据类型转换。例如,将导入的日期强制转换为SQL DATETIME。