【问题标题】:ORA-30926: unable to get a stable set of rows in the source tables when running Merge QueryORA-30926: 运行合并查询时无法在源表中获得一组稳定的行
【发布时间】:2021-08-05 05:14:10
【问题描述】:

我正在执行合并查询以更新表中的 2 列,但我收到以下错误“ORA-30926:无法在源表中获得一组稳定的行。

当我执行合并查询但我已经在 using 子句中使用了一个分区 by and where rn=1 以仅从源中提取非重复记录时,Oracle 仍然会抛出错误。

我能做些什么来解决这个问题?

MERGE
/*+ parallel(A) enable_parallel_dml*/
INTO
(
  SELECT
    PAY_RANGE_START_DATE_KEY,
    AA_PERSON_NATURAL_KEY,
    AA_PERSON_ASSIGNMENT_KEY,
    SCHEDULE_LINE_ID,
    SRC_CREATED_DATE,
    SRC_LAST_UPDATE_DATE
  FROM
    EDWFIN.PSP_LABOR_SCHD_DAY_F_ROLLUP
)
A USING
(
SELECT
  PAY_RANGE_START_DATE_KEY,
  AA_PERSON_NATURAL_KEY,
  AA_PERSON_ASSIGNMENT_KEY,
  SCHEDULE_LINE_ID,
  SRC_CREATED_DATE,
  SRC_LAST_UPDATE_DATE
FROM
  (
    SELECT
      PAY_RANGE_START_DATE_KEY,
      AA_PERSON_NATURAL_KEY,
      AA_PERSON_ASSIGNMENT_KEY,
      SCHEDULE_LINE_ID,
      SRC_CREATED_DATE,
      SRC_LAST_UPDATE_DATE,
      ROW_NUMBER() OVER ( PARTITION BY PAY_RANGE_START_DATE_KEY,
      AA_PERSON_NATURAL_KEY, AA_PERSON_ASSIGNMENT_KEY, SCHEDULE_LINE_ID,
      SRC_CREATED_DATE, SRC_LAST_UPDATE_DATE ORDER BY ROWNUM ) AS rn
    FROM
      EDWFIN.PSP_LABOR_SCHD_DAY_F_ROLLUP_FRS_356
  )
WHERE
  rn = 1
)
B ON
(
  A.PAY_RANGE_START_DATE_KEY = B.PAY_RANGE_START_DATE_KEY AND
  A.AA_PERSON_NATURAL_KEY    = B.AA_PERSON_NATURAL_KEY AND
  A.AA_PERSON_ASSIGNMENT_KEY = B.AA_PERSON_ASSIGNMENT_KEY AND
  A.SCHEDULE_LINE_ID         = B.SCHEDULE_LINE_ID
)
WHEN MATCHED THEN
  UPDATE
  SET
    A.SRC_CREATED_DATE     = B.SRC_CREATED_DATE,
    A.SRC_LAST_UPDATE_DATE = B.SRC_LAST_UPDATE_DATE
  WHERE
    A.SRC_CREATED_DATE      <> B.SRC_CREATED_DATE
  OR A.SRC_LAST_UPDATE_DATE <> B.SRC_LAST_UPDATE_DATE;
   COMMIT;

【问题讨论】:

    标签: sql oracle oracle11g oracle10g sql-merge


    【解决方案1】:

    我已经在 using 子句中使用了一个分区 by and where rn=1 来仅从源中提取非重复记录,但 Oracle 仍然抛出错误。

    你的

    ROW_NUMBER() OVER ( PARTITION BY PAY_RANGE_START_DATE_KEY,
          AA_PERSON_NATURAL_KEY, AA_PERSON_ASSIGNMENT_KEY, SCHEDULE_LINE_ID,
          SRC_CREATED_DATE, SRC_LAST_UPDATE_DATE ORDER BY ROWNUM ) AS rn
    

    带有过滤器rn=1 当您在 ON() 子句中使用 4 列时,将重复项删除 6 列。 此外,您正在使用另一个过滤器来过滤行以进行更新。

    得到你想要的最简单的方法是在USING子句中过滤所需的数据:

    MERGE
    /*+ parallel(A) enable_parallel_dml*/
    INTO
    (
      SELECT
        PAY_RANGE_START_DATE_KEY,
        AA_PERSON_NATURAL_KEY,
        AA_PERSON_ASSIGNMENT_KEY,
        SCHEDULE_LINE_ID,
        SRC_CREATED_DATE,
        SRC_LAST_UPDATE_DATE
      FROM
        EDWFIN.PSP_LABOR_SCHD_DAY_F_ROLLUP
    )
    A USING
    (
    SELECT
      PAY_RANGE_START_DATE_KEY,
      AA_PERSON_NATURAL_KEY,
      AA_PERSON_ASSIGNMENT_KEY,
      SCHEDULE_LINE_ID,
      SRC_CREATED_DATE,
      SRC_LAST_UPDATE_DATE
    FROM
      (
        SELECT
          BB.PAY_RANGE_START_DATE_KEY,
          BB.AA_PERSON_NATURAL_KEY,
          BB.AA_PERSON_ASSIGNMENT_KEY,
          BB.SCHEDULE_LINE_ID,
          BB.SRC_CREATED_DATE,
          BB.SRC_LAST_UPDATE_DATE,
          ROW_NUMBER() OVER ( 
             PARTITION BY BB.PAY_RANGE_START_DATE_KEY,
                          BB.AA_PERSON_NATURAL_KEY, 
                          BB.AA_PERSON_ASSIGNMENT_KEY, 
                          BB.SCHEDULE_LINE_ID
             ORDER BY ROWNUM /*?*/ 
             ) AS rn
        FROM
          EDWFIN.PSP_LABOR_SCHD_DAY_F_ROLLUP_FRS_356 BB
         ,EDWFIN.PSP_LABOR_SCHD_DAY_F_ROLLUP AA
        WHERE
          AA.PAY_RANGE_START_DATE_KEY = BB.PAY_RANGE_START_DATE_KEY AND
          AA.AA_PERSON_NATURAL_KEY    = BB.AA_PERSON_NATURAL_KEY AND
          AA.AA_PERSON_ASSIGNMENT_KEY = BB.AA_PERSON_ASSIGNMENT_KEY AND
          AA.SCHEDULE_LINE_ID         = BB.SCHEDULE_LINE_ID
          AND (
              AA.SRC_CREATED_DATE     <> BB.SRC_CREATED_DATE
           OR AA.SRC_LAST_UPDATE_DATE <> BB.SRC_LAST_UPDATE_DATE
          )
      )
    WHERE
      rn = 1
    )
    B ON
    (
      A.PAY_RANGE_START_DATE_KEY = B.PAY_RANGE_START_DATE_KEY AND
      A.AA_PERSON_NATURAL_KEY    = B.AA_PERSON_NATURAL_KEY AND
      A.AA_PERSON_ASSIGNMENT_KEY = B.AA_PERSON_ASSIGNMENT_KEY AND
      A.SCHEDULE_LINE_ID         = B.SCHEDULE_LINE_ID
    )
    WHEN MATCHED THEN
      UPDATE
      SET
        A.SRC_CREATED_DATE     = B.SRC_CREATED_DATE,
        A.SRC_LAST_UPDATE_DATE = B.SRC_LAST_UPDATE_DATE;
    

    如您所见,我在 USING 子句中过滤了您不需要的行,因此您在 UPDATE SET 中不需要 WHERE 子句,并删除了用于匹配的 4 列的重复项

    【讨论】:

    • 您建议的查询运行了很长时间,有没有办法像使用上述逻辑更新 118M 记录一样对其进行调整
    • 您需要提供更多信息:执行计划、sql 监视器、表 ddl 和统计信息等
    • 我已经单独添加了using子句的执行计划,因为现在单独运行需要2个多小时,到现在还没有完成
    • 好的,首先,将order by rownum替换为order by null,它将删除额外的操作couny。其次,您需要为两个表收集表统计信息,因为您的解释计划显示 1 行。
    • 我已将订单替换为 null 并在两个表上收集了统计信息。请在附件中找到最新的解释计划。
    猜你喜欢
    • 2014-03-23
    • 1970-01-01
    • 1970-01-01
    • 2011-01-21
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多