【问题标题】:Find out which row caused the error找出导致错误的行
【发布时间】:2010-05-11 13:45:55
【问题描述】:

我有一个动态编写的大查询以集成一些数据。基本上它的作用是查询一些表,连接一些其他表,处理一些数据,然后将其插入到最终表中。

问题是数据太多,我们不能真正相信来源,因为可能存在一些错误或不一致的数据。

例如,在使用客户的数据库进行开发时,我花了将近一个小时寻找错误,因为在我的大查询中间的某个地方,将一些 varchar 转换为 datetime 时出错。事实证明,他们有一些销售日期为“2009-02-29”,这是一个超出范围的日期。 是的,我知道。为什么将其存储为varchar?嗯,源数据库有 3 列日期,“月”、“日”和“年”。我不知道为什么会这样,但仍然如此。

但是,如果来源不可信,我该怎么处理呢?

我无法处理异常,我确实需要将原始消息提升到另一个级别,但我想提供更多信息,以便用户至少可以在致电我们之前尝试解决它。​​

所以我考虑向用户显示行号,或者至少可以让他知道他必须更正哪些记录的一些 ID。这也是一项艰巨的工作,因为有时集成会运行多达 80000 条记录。 而在 80000 条记录的集成中,一条虚拟错误消息:'将 varchar 数据类型转换为日期时间数据类型导致超出范围的日期时间值'根本没有任何意义。

所以任何想法都会受到赞赏。

哦,我正在使用带有 Service Pack 3 的 SQL Server 2005。


编辑:

好的,对于我所读到的答案,最好的办法是检查可能对引发错误至关重要的每一列,如果它们确实符合条件,我应该自己引发错误,并显示消息 I找到更具描述性的信息,并添加一些可能存储在单独表或一些变量中的信息,例如行的 ID 或其他一些根信息。

【问题讨论】:

    标签: sql-server sql-server-2005 tsql integration-testing


    【解决方案1】:

    对于日期,您可以使用 isdate 函数

    select ISDATE('20090229'),ISDATE('20090227')
    

    我通常插入到临时表中,进行检查,然后插入到真实表中

    【讨论】:

    • 当——我的回答与你所说的关于 staging 的答案几乎相同,但你更简洁明了。
    • 是的,暂存数据,清理数据,将数据加载到生产表中。
    【解决方案2】:

    我的建议是预先验证传入的数据,并在遇到错误时将记录搁置一旁。例如,检查无效日期。假设您在一组 80K 中找到 20 个。将这 20 个提取到单独的表中,并将错误消息附加到记录中。运行您的其他验证,然后最后将剩余(所有有效)记录导入所需的目标表。

    这可能会对性能产生太大影响,但可以让您轻松指出错误并允许它们被纠正,然后在第二遍中插入。

    【讨论】:

      【解决方案3】:

      这听起来像是一个标准的 ETL 问题:提取、转换和加载。 (除非您必须针对同一组数据一遍又一遍地运行此查询,在这种情况下,您几乎会做同样的事情,只是一遍又一遍。那么性能有多重要?)

      您可以提供什么样的错误处理和/或“不良数据报告”?如果您将所有内容都视为“一个大查询”,那么您的选择将变得非常有限-查询有效或无效,如果无效,我猜您最多会收到一条 RAISERROR 消息告诉调用者是什么。

      在这种情况下,我尝试建立的一般框架是:

      • 从源表开始
      • 生成一组您知道一致且格式正确(有效数据、键等)的临时表(SQLMenace 的临时表)
      • 针对这些表编写“不太大和胖的查询”

      这样做,您应该始终能够返回(或存储)一个有效的数据集......即使它是空的。诀窍在于确定例程何时失败 - 数据何时太损坏而无法处理并产生所需的结果,因此您返回一个措辞正确的错误消息?

      【讨论】:

      • 我可以将字符串作为错误消息返回给我的程序。但我可以在我的大查询中将其连接起来,以提供有关错误记录的一些信息。哦,正如您所指出的,查询有效或无效,我不打算捕捉错误,我打算指出它们。所以我会停止执行我发现的第一个错误,并向用户显示负责的记录。
      【解决方案4】:

      尝试这样的方法来查找行:

      ...big fat query here...
      WHERE ISDATE(YourBadVarcharColumn)!=1
      

      将数据加载到临时表中,其中大多数列是 varchar 并允许 NULL,其中您有一个状态列。

      像这样运行 UPDATE 命令

      UPDATE Staging
          SET Status='X'
          WHERE ISDATE(CONVERT(YourCharYear+YourCharMonth+YourCharDat+)!=1 
              OR OtherColumn<4...
      

      然后从您的暂存表中插入 Status!='X'

      INSERT INTO RealTable
              (col1, col2...)
          SELECT
              col1, col2, ...
              where Status!='X'
      

      【讨论】:

      • 然后您可以根据状态列轻松报告暂存表中的错误行
      猜你喜欢
      • 2016-12-15
      • 2021-08-12
      • 2016-11-20
      • 1970-01-01
      • 2013-10-14
      • 2022-01-03
      • 1970-01-01
      • 2013-05-27
      • 1970-01-01
      相关资源
      最近更新 更多