当一行的字段计数不正确时,您可以取消所有 VARCHAR 的 BULK INSERT 吗?
Can you cancel a BULK INSERT of all VARCHARs when a line's field count is incorrect?
我正在使用 BULK INSERT 将带分隔符的 .txt 文件加载到具有 5 列的暂存 table 中。 .txt 文件有时可能包含错误,并且每行的字段数 more/less 多于 5 个。如果出现这种情况,是否可以检测到并取消整个BULK INSERT?
每个 table 列都是 VARCHAR 类型。这样做是因为 header (H01) 和行(L0101、L0102 等)行包含不同类型的字段。因此,设置 MAXERRORS = 0 似乎不起作用,因为从技术上讲没有语法错误。结果事务被提交,catch 块永远不会激活,回滚也不会发生。行仍然被插入到 table 中错误地移动或聚集。
Expected .txt file format:
H01|Order|Date|Name|Address
L0101|Order|Part|SKU|Qty
L0102|Order|Part||Qty <-- Fields can be blank
L0103|Order|Part|SKU|Qty
Incorrect .txt file example:
H01|Order|Date|Name|Address
L0101|Order||Part|SKU|Qty <-- Extra field in the middle
||L0102|Order|Part|SKU|Qty <-- Extra fields at the beginning
L0103|Order|Part|SKU|Qty|| <-- Extra fields at the end
代码:
CREATE TABLE #TempStage (
Column1 VARCHAR(255) NULL
,Column2 VARCHAR(255) NULL
,Column3 VARCHAR(255) NULL
,Column4 VARCHAR(255) NULL
,Column5 VARCHAR(255) NULL
)
DECLARE
@dir SYSNAME
,@fname SYSNAME
,@SQL_BULK VARCHAR(255)
SELECT
@dir = '\sharedfolder\'
,@fname = 'testOrder.txt'
SET @SQL_BULK =
'BULK INSERT #TempStage FROM ''' + @dir + @fname + ''' WITH
(
FIRSTROW = 1,
DATAFILETYPE=''char'',
FIELDTERMINATOR = ''|'',
ROWTERMINATOR = ''0x0a'',
KEEPNULLS,
MAXERRORS = 0
)'
BEGIN TRY
BEGIN TRANSACTION
EXEC (@SQL_BULK)
COMMIT TRANSACTION
END TRY
BEGIN CATCH
ROLLBACK TRANSACTION
END CATCH
SELECT * FROM #TempStage
DROP TABLE #TempStage
预期输出:
Column1
Column2
Column3
Column4
Column5
H01
Order
Date
Name
Address
L0101
Order
Part
SKU
Qty
L0102
Order
Part
NULL
Qty
L0103
Order
Part
SKU
Qty
输出不正确,想取消以免发生这种情况(\ = 管道):
Column1
Column2
Column3
Column4
Column5
H01
Order
Date
Name
Address
L0101
Order
NULL
Part
SKU \ Qty
NULL
NULL
L0102
Order
Part \ SKU \ QTY
L0103
Order
Part
SKU
Qty\ |
SQL 服务器 2016,13.0.1742.0
正如之前许多人指出的那样:BULK INSERT 速度很快,但是 not very flexible,尤其是对于列不一致。
当您的输入可能包含错误数据时(从技术上讲,从 SQL 的角度来看,这就是您所描述的),您必须采用一种或多种不同的方法:
- 首先使用外部程序预处理和“清理”数据,或者
- BULK INSERT 到具有一个大 VARCHAR(MAX) 列的暂存 table,然后使用 SQL 自行解析和清理数据,然后使用您的方法将其移入 tables真正的列,或
- 使用 CLR code/tricks 有效地实现上面的 (1) and/or (2),或
- 写一个外部程序同时clean/pre-process和SqlBulkCopy数据到你的SQL服务器(代替BULK INSERT),或者
- 改为使用 SSMS(虽然仍然很难处理 bad/variable 列)
我在我的职业生涯中曾经或多次做过所有这些,它们都有些困难和耗时(工作很耗时,他们的运行-时间很不错)。
我已经创建了一种基本方法来执行我需要的操作:
加载暂存后 table,检查“|”的任何实例(或您使用的任何定界符),并在找到时引发错误。
IF EXISTS(SELECT * FROM #TempStage WHERE
Column1 LIKE '%|%'
OR Column2 LIKE '%|%'
OR Column3 LIKE '%|%'
OR Column4 LIKE '%|%'
OR Column5 LIKE '%|%'
)
RAISERROR('Incorrect file formatting; Pipe character found.', 16, 1);
我正在使用 BULK INSERT 将带分隔符的 .txt 文件加载到具有 5 列的暂存 table 中。 .txt 文件有时可能包含错误,并且每行的字段数 more/less 多于 5 个。如果出现这种情况,是否可以检测到并取消整个BULK INSERT?
每个 table 列都是 VARCHAR 类型。这样做是因为 header (H01) 和行(L0101、L0102 等)行包含不同类型的字段。因此,设置 MAXERRORS = 0 似乎不起作用,因为从技术上讲没有语法错误。结果事务被提交,catch 块永远不会激活,回滚也不会发生。行仍然被插入到 table 中错误地移动或聚集。
Expected .txt file format:
H01|Order|Date|Name|Address
L0101|Order|Part|SKU|Qty
L0102|Order|Part||Qty <-- Fields can be blank
L0103|Order|Part|SKU|Qty
Incorrect .txt file example:
H01|Order|Date|Name|Address
L0101|Order||Part|SKU|Qty <-- Extra field in the middle
||L0102|Order|Part|SKU|Qty <-- Extra fields at the beginning
L0103|Order|Part|SKU|Qty|| <-- Extra fields at the end
代码:
CREATE TABLE #TempStage (
Column1 VARCHAR(255) NULL
,Column2 VARCHAR(255) NULL
,Column3 VARCHAR(255) NULL
,Column4 VARCHAR(255) NULL
,Column5 VARCHAR(255) NULL
)
DECLARE
@dir SYSNAME
,@fname SYSNAME
,@SQL_BULK VARCHAR(255)
SELECT
@dir = '\sharedfolder\'
,@fname = 'testOrder.txt'
SET @SQL_BULK =
'BULK INSERT #TempStage FROM ''' + @dir + @fname + ''' WITH
(
FIRSTROW = 1,
DATAFILETYPE=''char'',
FIELDTERMINATOR = ''|'',
ROWTERMINATOR = ''0x0a'',
KEEPNULLS,
MAXERRORS = 0
)'
BEGIN TRY
BEGIN TRANSACTION
EXEC (@SQL_BULK)
COMMIT TRANSACTION
END TRY
BEGIN CATCH
ROLLBACK TRANSACTION
END CATCH
SELECT * FROM #TempStage
DROP TABLE #TempStage
预期输出:
Column1 | Column2 | Column3 | Column4 | Column5 |
---|---|---|---|---|
H01 | Order | Date | Name | Address |
L0101 | Order | Part | SKU | Qty |
L0102 | Order | Part | NULL | Qty |
L0103 | Order | Part | SKU | Qty |
输出不正确,想取消以免发生这种情况(\ = 管道):
Column1 | Column2 | Column3 | Column4 | Column5 |
---|---|---|---|---|
H01 | Order | Date | Name | Address |
L0101 | Order | NULL | Part | SKU \ Qty |
NULL | NULL | L0102 | Order | Part \ SKU \ QTY |
L0103 | Order | Part | SKU | Qty\ | |
SQL 服务器 2016,13.0.1742.0
正如之前许多人指出的那样:BULK INSERT 速度很快,但是 not very flexible,尤其是对于列不一致。
当您的输入可能包含错误数据时(从技术上讲,从 SQL 的角度来看,这就是您所描述的),您必须采用一种或多种不同的方法:
- 首先使用外部程序预处理和“清理”数据,或者
- BULK INSERT 到具有一个大 VARCHAR(MAX) 列的暂存 table,然后使用 SQL 自行解析和清理数据,然后使用您的方法将其移入 tables真正的列,或
- 使用 CLR code/tricks 有效地实现上面的 (1) and/or (2),或
- 写一个外部程序同时clean/pre-process和SqlBulkCopy数据到你的SQL服务器(代替BULK INSERT),或者
- 改为使用 SSMS(虽然仍然很难处理 bad/variable 列)
我在我的职业生涯中曾经或多次做过所有这些,它们都有些困难和耗时(工作很耗时,他们的运行-时间很不错)。
我已经创建了一种基本方法来执行我需要的操作:
加载暂存后 table,检查“|”的任何实例(或您使用的任何定界符),并在找到时引发错误。
IF EXISTS(SELECT * FROM #TempStage WHERE
Column1 LIKE '%|%'
OR Column2 LIKE '%|%'
OR Column3 LIKE '%|%'
OR Column4 LIKE '%|%'
OR Column5 LIKE '%|%'
)
RAISERROR('Incorrect file formatting; Pipe character found.', 16, 1);