SQL Server:查找导致TSQL失败的行(SSIS)

6

SQL Server 2005问题:

我正在进行一项数据转换项目,需要将80k+行从一个表移动到另一个表。当我运行TSQL时,会出现各种与转换类型有关的错误。是否有办法找出导致错误的行?

=====================

更新:

我正在执行INSERT INTO TABLE1 (...) SELECT ... FROM TABLE2 Table2只是一堆varchar字段,而TABLE1具有正确的类型。

此脚本将被放入sproc中,并从SSIS包中执行。 SSIS包首先将5个大型平面文件导入TABLE2。

以下是示例错误消息:“将char数据类型转换为datetime数据类型导致超出范围的datetime值。”

有许多日期字段。在TABLE2中,有类似于“02/05/1075”的出生日期数据值。我想检查每个导致错误的行,以便我可以向负责坏数据的部门报告,以便他们可以进行更正。


你能给我们一些错误的例子吗?你是用插入语句还是游标来移动数据?据我所知,实际上没有日志文件可以告诉你确切的错误是什么,但也许通过一些错误信息,我们可以指导你朝正确的方向前进。 - OhioDude
请更加注意您的标签选择。 - Joel Coehoorn
1
如果是类型转换的问题,可以使用ISNUMERIC和ISDATE函数来测试字符串是否能够成功地隐式转换为数字或日期。但是,根据我的经验,ISNUMERIC在处理逗号和空格方面存在缺陷。不过,是的,您的OP应该更具体地说明您遇到了什么错误。 - Mark Canlas
1
这也很可能取决于您正在执行的T-SQL代码,或者是在SSIS中,还是其他什么?我不认为没有详细信息就能回答这个问题。 - John Saunders
刚刚更新了我的问题并提供了更多细节。谢谢! - DeveloperMCT
SELECT * FROM YourTable WHERE ISDATE(YourDateColumn)!=1 - KM.
7个回答

5
这不是使用SSIS的正确方法。您应该从源到目标进行数据流,并在中间进行任何必要的转换。您将能够通过使用目标的错误输出来获取错误详细信息,事实上,还可以获取错误行。
我经常将目标的错误输出发送到另一个目标-文本文件或设置为允许包括在真实目标中无效的数据的表格。
实际上,在SSIS中以标准方式执行此操作,数据类型不匹配应该在设计时被检测到。

3

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

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

然后不断更改where子句中between部分的值。我曾经手动完成过这个过程,但是我意识到你可以通过循环使用一些.Net代码来自动拆分,捕获异常并逐渐缩小范围,直到找到抛出异常的行。


4
语法不正确,解决问题的想法很差。一旦纠正语法错误,它会起作用,但效率最低,真的需要手动完成而不是在程序包中运行。使用isdate()函数可以轻松识别错误的日期。 - HLGEM

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

2
我假设您使用INSERT INTO进行更新。
相反,尝试使用游标进行更新,使用异常处理来捕获错误并记录所有需要的内容:它失败的行号等。

2
同意8万行并不算太多,所以游标会到达那里;如果有多个错误,将会有所帮助。不要忘记在SQL 2005中可以使用try/catch,因此您可以存储失败的行,并继续处理已经成功的行。 - u07ch
1
好的观点,u07ch:插入所有未引发错误的内容,然后您可以只使用一个语句LEFT JOIN ... WHERE RIGHT.X IS NULL来检查那些没有插入的内容。如果有许多行失败,这将是比修复80000行中的1K出错行更好的解决方案。但最可能的是找到1-2个不同的原因就足够了,其他的应该是相同的,并且应该很容易修复。 - van

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 不为空的数据

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

编辑

有许多日期字段。在 TABLE2 中,Birthdate 有像 '02/05/1075' 的数据值。我想检查每一行造成错误的原因,以便我可以向负责坏数据的部门报告,让他们进行更正。

使用此方法返回所有错误日期行:

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

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

当然,您可以将异常表格内容发送给提供错误数据的人。

他确实说他已经在使用SSIS,而源->目标->错误并不是很难... - John Saunders
我同意,这就是我会做的方式,但是SSIS并不容易学习如何正确使用,而且他可能面临时间压力。我知道这是从多年的DTS包处理经验中得出的结论,如果我没有接受过正式的SSIS培训,我永远不会想到使用这种方法。显然,他正在使用t-sql脚本而不是数据流,因此他可能完全不知道如何使用数据流。第一次尝试并不容易。 - HLGEM
你知道吗,我从没想过他会使用SSIS却不用数据流。 - John Saunders
如果您的DTS包都基于Exec SQL任务,则在进行转换时,它们将不会使用数据流。并且当您转换数百个包时,除非您正在进行重大更改,否则不会修复它们以执行此操作。如果您真的不知道数据流是什么,您可能会查看转换后的DTS包,并认为这是设置新包的最佳方法。我想,许多从SSIS开始的人使用它与从DTS开始的人非常不同。 - HLGEM
大家好,我正在使用数据流将txt文件移动到表中。有100多个字段和一个以上的日期字段导致了错误。我选择将所有数据导入具有简单varchar(允许一切)的表中,然后在T-SQL中更正数据,以便我拥有更强大和灵活的控制权。我不是要在过程中处理/修复这些错误,而是在原始系统中查找坏数据并进行修复。例如,一些员工的出生日期是1080年。 - DeveloperMCT

0

如果你正在使用游标,那么是很简单的。如果你不使用游标,我认为不是这样,因为 SQL 操作本身就是 ACID 或事务。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接