Sql 查询不会更新所有行
有一张相当大的桌子,超过10000行。它有OBJ_ID、更改日期、用户列。我添加了一个新的列,RECORD_ID,它现在是空的。 我需要对其进行更新,以便记录的ID应具有对象ID和更改日期的升序数值。 我想到了这个:Sql 查询不会更新所有行,sql,oracle,plsql,Sql,Oracle,Plsql,有一张相当大的桌子,超过10000行。它有OBJ_ID、更改日期、用户列。我添加了一个新的列,RECORD_ID,它现在是空的。 我需要对其进行更新,以便记录的ID应具有对象ID和更改日期的升序数值。 我想到了这个: CREATE SEQUENCE REC_ID_SEQ START WITH 1 INCREMENT BY 1 CACHE 100; / CREATE OR REPLACE TRIGGER TRG_REC_ID_SEQ
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;
/
但是当命令停止工作时,没有错误,我看到大约一半的行没有更新。如何正确执行此操作?使用MERGE命令和rowid pseudocolumn替换主键:
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;
现场演示:类似于@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;
这个看起来很贵。为什么不通过obj_id、变更日期更新订单上的SET record_id=行号;在这种构造@Kaushik中使用rowid是非常好的——它们不会改变,因为Oracle保证您对数据有一个读取一致的视图。正如JNevill所说,使用set操作可能更可取……Kaushik-Nayak,这个表没有PK。JNevill,听起来很合理,我现在就试试!不幸的是,JNevill的想法行不通。ORA-30483:此处不允许使用窗口函数。看起来它必须在oracle的子查询中完成。更新t1 SET record_id=t1.RowNum,从表t1中选择obj_id_id,更改日期,按obj_id更改订单上的行数,更改日期为RowNum,或沿着这些行的其他内容。