【问题标题】:SQL Server: Find out what row caused the TSQL to fail (SSIS)SQL Server:找出导致 TSQL 失败的行 (SSIS)
【发布时间】:2010-11-08 19:57:51
【问题描述】:

SQL Server 2005 问题:

我正在处理一个数据转换项目,我正在处理 80k+ 行并将它们从一个表移动到另一个表。当我运行 TSQL 时,它会出现与转换类型或其他有关的各种错误。有没有办法找出导致错误的行?

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

更新:

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

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

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

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

【问题讨论】:

  • 你能给我们一些错误的例子吗?您如何使用插入语句或游标移动数据?据我所知,确实没有日志文件可以准确地告诉您错误是什么,但也许通过一些错误消息,我们可以为您指明正确的方向。
  • 请注意您的标签选择。
  • 如果是转换问题,可以使用 ISNUMERIC 和 ISDATE 函数分别帮助测试字符串是否可以成功地隐式转换为数字或日期。根据我的经验,ISNUMERIC 虽然在逗号和空格方面存在缺陷。但是,是的,您的 OP 应该更具体地说明您遇到的错误。
  • 这也可能取决于您正在执行的 T-SQL 代码,或者这是否在 SSIS 中,还是什么?如果没有细节,我看不出如何回答这个问题。
  • 刚刚更新了我的问题,提供了更多详细信息。谢谢!

标签: sql-server sql-server-2005 tsql ssis


【解决方案1】:

不完全是游标,但同样有效 - 我有超过 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】:

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

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

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

    【讨论】:

    • 语法不正确,解决问题的想法很糟糕。它会起作用(一旦纠正了语法错误),但它效率最低,并且确实需要手动完成,而不是在包中运行。使用 isdate() 函数可以轻松识别错误日期。
    【解决方案3】:

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

     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,而且 Source -> Dest -> 错误不是很难...
    • 我同意,我会这样做,但是SSIS不容易学习如何正确使用,他可能有时间压力。我知道多年从事 DTS 软件包的工作,如果我没有接受过正式的 SSIS 培训,我永远不会想到这种方法。显然他使用的是 t-sql 脚本而不是数据流,因此他可能完全不知道如何使用数据流。第一次做这件事并不容易。
    • 你知道,我从来没有想过他可能正在使用 SSIS 而正在使用数据流。
    • 好吧,如果你的 DTS 包都是基于 Exec SQL 任务的,那么当你转换时,它们就不会使用数据流。当您转换数百个时,除非您进行重大更改,否则您不会进入并修复它们。如果您真的不知道 Data Flow 的作用,您可能会查看转换后的 DTS 包并认为这是设置新包的最佳方式。我想许多开始使用 SSIS 的人使用它的方式与许多开始使用 DTS 的人截然不同。
    • 伙计们,我正在使用数据流将 txt 文件移动到表中。有超过一百个字段和多个日期字段导致错误。我选择使用简单的 varchar(允许一切)将所有数据导入到一个表中,然后在 T-SQL 中更正数据,我觉得我有更多的权力和灵活性。我并不想在这个过程中处理/修复这些错误,而是在原始系统中找到错误数据并修复它。例如,有些员工的生日是 1080 年。
    【解决方案4】:

    如果您正在循环,请在循环中添加打印。

    如果您使用基于集合的操作,请添加限制性 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 的新转换数据

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

    编辑

    有很多日期字段。在表 2 中, 有像这样的数据值 '02/05/1075' 代表生日。我想要 检查导致 错误,所以我可以报告给 负责坏事的部门 数据,以便他们进行更正。

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

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

    【讨论】:

      【解决方案5】:

      这不是使用 SSIS 的方法。您应该拥有从源到目的地的数据流,中间包含您需要的任何转换。通过使用目标的错误输出,您将能够获取错误详细信息,实际上是错误行。

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


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

      【讨论】:

        【解决方案6】:

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

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

        【讨论】:

        • 同意 80k 行并不多,所以光标会到达那里;如果有多个错误会有所帮助。不要忘记您可以在 sql 2005 中执行 try/catch,这样您就可以存储失败的行并继续处理那些有效的行。
        • 好点,u07ch:插入所有未引发错误的内容,然后您只需 LEFT JOIN ... WHERE RIGHT.X IS NULL 即可检查未在一个语句中全部插入的内容。如果有很多行失败,这将是最好的解决方案,而不是修复 80K 中的 1K 错误行。但很可能找到 1-2 个不同的原因就足够了,其他的应该是相同的并且应该很容易修复。
        【解决方案7】:

        如果您正在使用游标,是的,而且是微不足道的。如果你不使用游标,我不这么认为,因为 SQL 操作是ACID,或者本身就是事务。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多