异常表

异常表是用户创建的表,用于模拟指定要使用带有 IMMEDIATE CHECKED 选项的 SET INTEGRITY 语句进行检查的表的定义。 它们用于存储违反要检查的表中的约束的行的副本。

LOAD 实用程序使用的异常表与此处描述的异常表相同,因此可以在使用 SET INTEGRITY 语句进行检查期间复用这些异常表。

创建异常表的规则

创建异常表的规则如下所示:

  • 如果表受安全策略保护,那么异常表必须受同一安全策略保护。
  • 异常表的前 n 列与要检查的表的列相同。 所有列属性 (包括名称,数据类型和长度) 都应该相同。 对于受保护的列,保护该列的安全标号在两个表中必须相同。
  • 异常表的所有列都必须不含约束和触发器。 约束包括引用完整性和检查约束以及可能导致插入错误的唯一索引约束。
  • 异常表的 (n+1) 列是可选的 TIMESTAMP 列。 如果在发出 SET INTEGRITY 语句以检查数据之前未删除异常表中的行,那么这将标识同一表上的 SET INTEGRITY 语句对检查的连续调用。 时间戳记精度可以是从 0 到 12 的任何值,并且分配的值将是 CURRENT TIMESTAMP 专用寄存器的结果
  • (n+2) 列的类型应该为 CLOB (32K) 或更大。 此列是可选的,但建议使用此列,它将用于提供行中数据违反的约束的名称。 如果未提供此列 (例如,如果原始表具有允许的最大列数) ,那么将仅复制检测到约束违例的行。
  • 应该使用 (n+1)(n+2) 列创建异常表。
  • 对于先前列示的其他列,不强制使用任何特定名称。 但是,必须完全遵循类型规范。
  • 不允许其他列。
  • 如果原始表具有生成的列 (包括 IDENTITY 属性) ,那么异常表中的相应列不应指定生成的属性。
  • 调用 SET INTEGRITY 语句以检查数据的用户必须拥有对异常表的 INSERT 特权。
  • 异常表不能是数据分区表、范围集群表或者已拆离的表。
  • 异常表不能是具体化查询表或登台表。
  • 异常表不能具有任何从属刷新立即具体化查询表或任何从属传播立即登台表。

message 列中的信息具有以下结构:

表 1. 异常表消息列结构
字段号 内容 大小 注释
1 约束违例数 5 字节 右对齐填充了 0
2 第一个约束违例的类型 1 个字节
  • D -删除级联违例
  • F -外键违例
  • G -生成的列违例
  • I -唯一索引违例a
  • K -检查约束违例
  • L -LBAC 写规则违例
  • P -数据分区违例
  • S -行安全标签无效
  • X -针对 XML 列违例定义的索引d
3 约束/列b /index IDc 的长度 5 字节 右对齐填充了 0
4 约束名称/列名b/index IDc 上一个字段的长度  
5 分隔符 3 字节 <空格><冒号><空格>
6 下一个约束违例的类型 1 个字节
  • D -删除级联违例
  • F -外键违例
  • G -生成的列违例
  • I -唯一索引违例
  • K -检查约束违例
  • L -LBAC 写规则违例
  • P -数据分区违例
  • S -行安全标签无效
  • X -针对 XML 列违例定义的索引d
7 约束/列/索引标识的长度 5 字节 右对齐填充了 0
8 约束名称/列名/索引标识 上一个字段的长度  
..... ..... ..... 针对每个违例重复字段 5 到 8
  • 使用 SET INTEGRITY 语句进行检查期间不会发生唯一索引违例,除非是在连接操作之后。 但是,如果选择了 FOR EXCEPTION 选项,那么在运行 LOAD 时将报告此情况。 但是, LOAD 不会报告异常表中的检查约束,生成的列,外键,删除级联或数据分区违例。
  • b 要从目录视图中检索生成的列的表达式,请使用 SELECT 语句。 例如,如果字段 4 为 MYSCHEMA.MYTABLE.GEN_1,那么 SELECT SUBSTR (TEXT , 1 , 50) FROM SYSCAT.COLUMNS WHERE TABSCHEMA = 'MYSCHEMA' AND TABNAME = 'MYNAME' AND COLNAME = 'GEN_1'; 将返回表达式的前 50 个字节,格式为 AS (<expression>)
  • c 要从目录视图检索索引标识,请使用 SELECT 语句。 例如,如果字段 4 是 1234 ,那么 SELECT INDSCHEMA , INDNAME FROM SYSCAT.INDEXES WHERE IID=1234。
  • d 对于针对 XML 列违例定义的索引,约束名称,列名或索引标识字段标识在其某个索引中具有完整性违例的 XML 列。 它不会识别存在完整性违例的索引。 它仅标识发生索引违例的 XML 列的名称。 例如,消息列中的值 X00006XTCOLZ 指示在 XTCOL2 列的其中一个索引中发生了索引违例。

处理异常表中的行

可以通过各种方式处理异常表中的信息。 可以更正数据并将行重新插入到原始表中。

如果原始表上没有 INSERT 触发器,请通过在异常表上发出带有子查询的 INSERT 语句来传输更正后的行。

如果存在 INSERT 触发器,并且您希望使用来自异常表的更正行来完成装入操作,而不触发触发器:
  • 设计要触发的 INSERT 触发器,具体取决于为实现此目的而显式定义的列中的值。
  • 从异常表中卸载数据,并使用 LOAD 实用程序将其追加。 在这种情况下,如果要重新检查数据,请注意约束检查不会限制在附加行中。
  • 保存相关系统目录视图中的触发器定义文本。 然后,删除 INSERT 触发器并使用 INSERT 从异常表中传输更正后的行。 最后,使用已保存的触发器定义重新创建触发器。

未进行显式配置以防止在从异常表插入行时触发触发器。

对于唯一索引违例,每行仅报告一个违例。

如果表中包含 LONG VARCHAR , LONG VARGRAPHIC 或 LOB 数据类型的值,那么在发生唯一索引违例的情况下,不会将这些值插入到异常表中。

查询异常表

异常表中的消息列结构是约束名称,长度和定界符的并置列表,如前所述。 可以查询此信息。

例如,要检索所有违例的列表 (仅使用约束名称重复每行) ,请假定原始表 T1 有两列: C1 和 C2。 另外,假定相应的异常表 E1具有对应于 T1中的列 C1 和 C2以及消息列 MSGCOL。 以下查询使用递归来列出每行一个约束名称 (重复具有多个违例的行):
WITH IV  (C1, C2, MSGCOL, CONSTNAME, I, J) AS
 (SELECT C1, C2, MSGCOL,
     CHAR(SUBSTR(MSGCOL, 12,
                 INTEGER(DECIMAL(VARCHAR(SUBSTR(MSGCOL,7,5)),5,0)))),
     1,
     15+INTEGER(DECIMAL(VARCHAR(SUBSTR(MSGCOL,7,5)),5,0))
    FROM E1
  UNION ALL
  SELECT C1, C2, MSGCOL,
      CHAR(SUBSTR(MSGCOL, J+6,
                  INTEGER(DECIMAL(VARCHAR(SUBSTR(MSGCOL,J+1,5)),5,0)))),
      I+1,
      J+9+INTEGER(DECIMAL(VARCHAR(SUBSTR(MSGCOL,J+1,5)),5,0))
    FROM IV
    WHERE I < INTEGER(DECIMAL(VARCHAR(SUBSTR(MSGCOL,1,5)),5,0))
 ) SELECT C1, C2, CONSTNAME FROM IV;
要列出违反特定约束的所有行,可按如下所示扩展先前查询:
WITH IV  (C1, C2, MSGCOL, CONSTNAME, I, J) AS
 (SELECT C1, C2, MSGCOL,
      CHAR(SUBSTR(MSGCOL, 12,
                  INTEGER(DECIMAL(VARCHAR(SUBSTR(MSGCOL,7,5)),5,0)))),
      1,
      15+INTEGER(DECIMAL(VARCHAR(SUBSTR(MSGCOL,7,5)),5,0))
    FROM E1
  UNION ALL
  SELECT C1, C2, MSGCOL,
      CHAR(SUBSTR(MSGCOL, J+6,
                 INTEGER(DECIMAL(VARCHAR(SUBSTR(MSGCOL,J+1,5)),5,0)))),
      I+1,
      J+9+INTEGER(DECIMAL(VARCHAR(SUBSTR(MSGCOL,J+1,5)),5,0))
    FROM IV
    WHERE I < INTEGER(DECIMAL(VARCHAR(SUBSTR(MSGCOL,1,5)),5,0))
 ) SELECT C1, C2, CONSTNAME FROM IV WHERE CONSTNAME = 'constraintname';
可以使用以下查询来获取所有检查约束违例:
WITH IV  (C1, C2, MSGCOL, CONSTNAME, CONSTTYPE, I, J) AS
  (SELECT C1, C2, MSGCOL,
       CHAR(SUBSTR(MSGCOL, 12,
                   INTEGER(DECIMAL(VARCHAR(SUBSTR(MSGCOL,7,5)),5,0)))),
       CHAR(SUBSTR(MSGCOL, 6, 1)),
       1,
       15+INTEGER(DECIMAL(VARCHAR(SUBSTR(MSGCOL,7,5)),5,0))
     FROM E1
   UNION ALL
   SELECT C1, C2, MSGCOL,
       CHAR(SUBSTR(MSGCOL, J+6,
                  INTEGER(DECIMAL(VARCHAR(SUBSTR(MSGCOL,J+1,5)),5,0)))),
       CHAR(SUBSTR(MSGCOL, J, 1)),
       I+1,
       J+9+INTEGER(DECIMAL(VARCHAR(SUBSTR(MSGCOL,J+1,5)),5,0))
     FROM IV
     WHERE I < INTEGER(DECIMAL(VARCHAR(SUBSTR(MSGCOL,1,5)),5,0))
 ) SELECT C1, C2, CONSTNAME FROM IV WHERE CONSTTYPE = 'K';