【问题标题】:Query doesn't update all rows查询不会更新所有行
【发布时间】:2017-12-23 00:09:27
【问题描述】:

有相当大的表,超过 10 000 000 行。它有 OBJ_ID、DATE_OF_CHANGE、USER 列。我添加了一个新列,RECORD_ID,它现在是空的。 我需要更新它,因此 RECORD_ID 的 OBJ_ID 和 DATE_OF_CHANGE 的数值应该是递增的。 我想出了这个:

 CREATE SEQUENCE REC_ID_SEQ
      START WITH 1
      INCREMENT BY 1
      CACHE 100;
    /
    CREATE OR REPLACE TRIGGER TRG_REC_ID_SEQ
      BEFORE INSERT ON T_HISTORY
      FOR EACH ROW
    BEGIN
      :NEW.RECORD_ID := REC_ID_SEQ.NEXTVAL;
    END;
    /

    DECLARE
       O_ID NUMBER := 0;
       S_DATE DATE := SYSDATE;
       HIST_NUM NUMBER := 0;       
       LOOP_COUNT NUMBER := 0;

    BEGIN

      FOR O IN (SELECT ROWID ROW_ID, D.* FROM T_HISTORY D ORDER BY D.OBJ_ID, D.DATE_OF_CHANGE)

      LOOP

          LOOP_COUNT := LOOP_COUNT + 1;
          IF O.OBJ_ID != O_ID OR O.DATE_OF_CHANGE!= S_DATE 
          THEN 
            HIST_NUM := HIST_NUM + 1; 
          END IF;


          UPDATE T_HISTORY T SET T.RECORD_ID = HIST_NUM WHERE T.ROWID = O.ROW_ID;     

          O_ID := O.OBJ_ID;
          S_DATE := O.DATE_OF_CHANGE; 

          IF LOOP_COUNT > 100000 THEN
          COMMIT; LOOP_COUNT := 0;
          END IF;

      END LOOP;
    END;
    /

但是当命令停止工作(没有错误)时,我看到大约一半的行没有更新。我该如何以正确的方式做到这一点?

【问题讨论】:

  • 这看起来真的很贵。为什么不只是 UPDATE <table> SET record_id = ROW_NUMBER() OVER (ORDER BY obj_id, date_of_change; 让它撕裂。
  • 在这种构造 @Kaushik 中使用 rowid 非常好——它们不会改变,因为 Oracle 保证您的数据具有读取一致性视图。正如 JNevill 所说,使用集合操作可能更可取......
  • Kaushik Nayak,这张桌子没有PK。 JNevill,听起来很合理,我现在就试试!
  • 很遗憾,JNevill 的想法行不通。 “ORA-30483:此处不允许使用窗口函数”。
  • 看起来必须在oracle的子查询中完成。 UPDATE t1 SET record_id = t1.RowNum FROM (SELECT obj_id_id, date_of_change, ROW_NUMBER() OVER (ORDER BY obj_id, date_of_change) AS rowNum FROM table) t1 或类似的东西。

标签: sql oracle plsql


【解决方案1】:

使用MERGE 命令和rowid 伪列代替主键:

merge into T_HISTORY t
using (
  select rownum as xx, t.* 
  from ( 
    select t.*, rowid as x_rowid 
    from T_HISTORY t
    order by OBJ_ID, DATE_OF_CHANGE
  ) t
) xx
on (xx.x_rowid = t.rowid )
when matched then update
set t.RECORD_ID = xx;

现场演示:http://sqlfiddle.com/#!4/aad05/2

【讨论】:

    【解决方案2】:

    类似于@krokodilko 的解决方案,使用解析函数:

    MERGE INTO t_history t
         USING (SELECT obj_id,
                       date_of_change,
                       ROW_NUMBER () OVER (ORDER BY obj_id, date_of_change) rn
                  FROM t_history) r
            ON (t.obj_id = r.obj_id AND t.date_of_change = r.date_of_change)
    WHEN MATCHED
    THEN
       UPDATE SET t.record_id = r.rn;
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-09-29
      • 1970-01-01
      • 1970-01-01
      • 2017-01-07
      • 1970-01-01
      • 2021-09-12
      相关资源
      最近更新 更多