如何找出导致 T-SQL 语句失败的行

问题描述 投票:0回答:7

我正在开展一个数据转换项目,其中我要获取 80k 多行并将它们从一个表移动到另一个表。当我运行 T-SQL 语句时,它失败并出现与转换类型或其他相关的各种错误。有没有办法找出哪一行导致了错误?

我正在执行

INSERT INTO TABLE1 (...) SELECT ... FROM TABLE2
声明。 Table2 只是一堆 varchar 字段,其中 TABLE1 具有正确的类型。

该脚本将被放入存储过程中并从 SSIS 包中执行。 SSIS 包首先将 5 个大的平面文件导入到 TABLE2 中。

这是错误消息示例:

将 char 数据类型转换为日期时间数据类型导致日期时间值超出范围。

有很多日期字段。在表 2 中,有诸如

02/05/1975
之类的数据值表示出生日期。我想检查导致错误的每一行,这样我就可以向负责错误数据的部门报告,以便他们可以纠正它。

sql-server sql-server-2005 t-sql ssis
7个回答
5
投票

这不是 SSIS 的做法。您应该让数据从源流到目的地,并在中间进行任何所需的转换。您将能够通过使用目标的错误输出来获取错误详细信息,实际上,还可以获取错误行。

我经常将一个目的地的错误输出发送到另一个目的地 - 文本文件或设置为允许所有内容的表,包括在真实目的地中无效的数据。


实际上,如果您在 SSIS 中按照标准方式执行此操作,那么应该在设计时检测到数据类型不匹配。


3
投票

我所做的就是使用 WHERE 子句将行集分成两半:

INSERT MyTable(id, datecol) SELECT id, datecol FROM OtherTable WHERE ID BETWEEN 0 AND 40,000

然后不断更改 where 子句之间部分的值。我已经多次手动完成此操作,但我突然想到,您可以在循环中使用一些 .Net 代码自动进行分割,捕获异常,然后将其范围缩小到仅抛出异常的行,一点一点地。


2
投票

我假设您使用 INSERT INTO ...进行更新

而是尝试使用游标进行更新,使用异常处理来捕获错误并记录您需要的所有内容:失败的行号等。


2
投票

不完全是一个游标,但同样有效 - 我有超过 400 万行需要检查,并有多个转换失败。这是我使用的,它产生了两个临时表,一个包含我的所有值和分配的行,另一个只包含第一个临时表中无法转换的行列表。

select row_number() over (order by TimeID) as rownum,timeID into #TestingTable from MyTableWithBadData

set nocount on
declare @row as int
declare @last as int
set @row=0
select @last = count(*) from #TestingTable
declare @timeid as decimal(24,0)
create table #fails (rownum int)
while @row<=@last
begin
    Begin Try
        select @timeid=cast(timeID as decimal(24,0)) from #TestingTable where rownum = @row 
    end try
    begin catch 
        print cast(@row as varchar(25)) + ' : failed'
        insert into #fails(rownum) values(@row)
    end catch
    set @row = @row+1
end

1
投票

如果要循环,请在循环中添加打印内容。

如果您使用基于集合的操作,请添加限制性 WHERE 条件并运行它。继续运行它(每次都使其限制越来越多),直到您可以在数据中找到该行。如果您可以运行 N 行块,那么只需选择这些行并查看它们即可。

添加 CASE 语句来捕获问题(将错误值转换为 NULL 或其他值)并将一个值放入新的 FlagColumn 中,告诉您问题的类型:

CASE WHEN ISNUMERIC(x)!=1 then NULL ELSE x END as x
,CASE WHEN ISNUMERIC(x)!=1 then 'not numeric' else NULL END AS FlagColumn

然后选择新转换的数据,其中 FlagColumn IS NOT NULL

您可以尝试在源数据的各个列上使用带有 isnumeric() 或 isdate() 函数的 select 语句

编辑

有很多日期字段。在表2中, 有像这样的数据值 生日为“02/05/1075”。我想要 检查导致的每一行 错误,所以我可以向 不良责任部门 数据,以便他们可以纠正它。

使用它返回所有错误的日期行:

SELECT * FROM YourTable WHERE ISDATE(YourDateColumn)!=1

0
投票

如果您正在使用光标,是的,而且很简单。如果您不使用游标,我不这么认为,因为 SQL 操作是ACID,或者事务本身。


0
投票

John Sauders 的想法是正确的,有更好的方法可以使用 SSIS 进行此类处理。然而,学习 SSIS 并重做你的包以完全改变流程目前可能不是一个选择,所以我提供这个建议。您似乎遇到了日期不正确的问题。因此,首先运行一个查询来识别那些错误的记录,并将它们插入到执行表中。然后只插入剩下的记录。比如:

 insert exceptiontable (field1, field2)
 select field1, field2 from table2 where isdate(field2) = 0

 insert table1 (field1, field2)
 select field1, field2 from table2 where isdate(field2) = 1

当然你可以将异常表的内容发送给提供不良数据的人。

© www.soinside.com 2019 - 2024. All rights reserved.