我对UPDATE
声明的用法有疑问。有没有办法让我只用SQL编写以下场景而不是编写存储过程?
我试图简化案例。
myTable
有4列,其值如下:
COMP1 COMP2 NO ACTIVE
0 0 4 N
4 1 Y
2 2 21 Y
3 1 1 Y
1 3 43 Y
2 1 Y
3 1 12 Y
2 2 0 Y
3 2 Y
1 1 5 N
WHERE ACTIVE = 'Y'
并开始更新
它们的值在NO列中按COMP1, COMP2 ASC
排序。编号必须从表MAX(NO)
WHERE ACTIVE = 'N'
值开始
具有相同COMP1和COMP2的行将具有相同的NO值。
(评论后更新)NO列不总是NULL。此列中存在错误值,需要通过更新查询进行更正。
这样,在UPDATE
语句执行后,myTable
将如下(如果我们订购的话)
COMP1 COMP2 NO ACTIVE
0 0 4 N
1 1 5 N
1 3 6 Y
2 1 7 Y
2 2 8 Y
2 2 8 Y
3 1 9 Y
3 1 9 Y
3 2 10 Y
4 1 11 Y
我想知道我是否能够在不需要选择整个列表并在存储过程中循环使用CURSOR的情况下完成此操作。
(更新:我已经编写了SP。简化版本如下。由于我更改了所有名称并删除了许多条件,因此可能会出现问题。)
PROCEDURE updateAllNo
IS
CURSOR c1
IS
SELECT *
FROM MyTable SE
WHERE SE.ACTIVE = 'Y'
ORDER BY SE.COMP1, SE.COMP2;
v_last_no NUMBER := 0;
v_last_comp2 DATE := SYSDATE + 100;
v_last_comp1 DATE := SYSDATE + 100;
v_now_comp2 DATE := SYSDATE;
v_now_comp1 DATE := SYSDATE;
BEGIN
SELECT MAX (SE.NO)
INTO v_last_no
FROM MyTable SE
WHERE SE.ACTIVE = 'N';
SELECT MAX (SE.COMP1), MAX (SE.COMP2)
INTO v_last_comp1, v_last_comp2
FROM MyTable SE
WHERE SE.ISLEMBASARILI = 'E'
AND SE.NO = v_last_no;
FOR r1 IN c1
LOOP
BEGIN
v_now_comp2 := r1.COMP2;
v_now_comp1 := r1.COMP1;
IF v_now_comp2 != v_last_comp2 OR v_now_comp1 != v_last_comp1
THEN
v_last_no := v_last_no + 1;
END IF;
UPDATE MyTable SE
SET SE.NO = v_last_no
WHERE SEQ_ID = r1.seq_id;
v_last_comp2 := v_now_comp2;
v_last_comp1 := v_now_comp1;
END;
END LOOP;
COMMIT;
END;
我使用的是Oracle 11g。
答案 0 :(得分:1)
可以使用窗口函数检索新数字:
以下内容将检索活动行并计算no
select comp1,
comp2,
row_number() over (order by comp1, comp2) + (select max(no) from mytable where active = 'N') as rn
from mytable
where active = 'Y'
现在可以在MERGE
语句中使用它来对表运行更新。由于该表显然没有PK,我将使用ROWID
来匹配行:
merge into mytable tg
using (
select rowid as rid,
comp1,
comp2,
row_number() over (order by comp1, comp2) + (select max(no) from mytable where active = 'N') as rn
from mytable
where active = 'Y'
) t on (t.rid = tg.rowid)
when matched then update
set no = t.rn;
这肯定比单行更新的循环更快 - 特别是对于较大的表。
答案 1 :(得分:0)
我假设NO
时字段ACTIVE='Y'
始终为空。如果是这种情况,则无论是否指定WHERE ACTIVE = 'N'
条件,MAX(NO)都将返回相同的值。有了这个假设,这个UPDATE
语句应该可以解决问题。
UPDATE myTable
SET NO = (SELECT MAX(NO) FROM myTable) + 1
WHERE ROWID IN
(SELECT ROWID FROM myTable
WHERE ACTIVE = 'Y'
ORDER BY COMP1, COMP2);