我正在尝试根据rownumber更新列。表Unpaid1包含多个帐户的多个事务。当我执行以下脚本时,我经常以不正确的序列号(Cycleage)结束事务,如下所示。循环次数应从最旧到最新的顺序为1到4。可能是这个问题的原因是什么?还有另一种分配循环的方法吗?
Begin
For X in (Select * From temp_Unpaid1 order by trxnserno asc)
loop
Update temp_Unpaid1 t set t.cycleage = rownum where t.custid=x.custid;
end loop;
End;
+-----------+-----------+--------+--------+----------+
| TRXNSERNO | CUSTID | AMOUNT | DATE | CYCLEAGE |
+-----------+-----------+--------+--------+----------+
| 66 | 45 | -10 | 08.jan | 2 |
| 67 | 45 | -20 | 10.jan | 1 |
| 90 | 45 | -30 | 15.jan | 3 |
| 155 | 45 | -15 | 20.jan | 4 |
+-----------+-----------+--------+--------+----------+
答案 0 :(得分:1)
问题是更新中的ROWNUM是SELECT语句的独立,事实上,它看起来像是在进行不必要的更新。原因如下:
SELECT将按TRXNSERNO的顺序返回所有行,即使你只有一个custid,你也会得到4行具有相同的custid:
CUSTID TRXNSERNO ...(other columns)
45 66
45 67
45 90
45 155
然后对于这些行中的每个,将运行update语句(因此您将更新相同的4行4次。)
当UPDATE运行时,它会找到custid 45的4行(它不知道/关心TRXNSERNO在SELECT中的内容)并以它找到的顺序更新它们。 (UPDATE语句中没有任何内容强制更新行的顺序。)
因此,无论第4次和最后一次更新发现它们的顺序是如何分配ROWNUM值,所以如果Oracle按照
的顺序找到它们CUSTID TRXNSERNO
45 67
45 66
45 90
45 155
然后ROWNUM值将按以下顺序排列:
CUSTID TRXNSERNO ROWNUM
45 67 1
45 66 2
45 90 3
45 155 4
在另一次运行中(取决于具体情况),Oracle可能会执行更新并以完全不同的顺序查找custid 45行,如下所示,并相应地为它们分配rownums:
CUSTID TRXNSERNO ROWNUM
45 155 1
45 66 2
45 90 3
45 67 4
您可以保留当前代码,但只需在SELECT列表中生成ROWNUM,并将更新中的值应用于custid / trxnserno对:
Begin
For X in
(Select tmp.*
, row_number() over (partition by tmp.custid order by tmp.trxnserno) as rn
From temp_Unpaid1 tmp)
loop
Update temp_Unpaid1 t
set t.cycleage = rn
where t.custid=x.custid
and t.trxnserno = x.trxnserno;
end loop;
End;
或者,您可以在单个SQL语句中尝试使用MERGE之类的内容并仅使用WHEN MATCHED部分:
MERGE INTO temp_unpaid1 temp
USING
(Select t.*
, row_number() over (partition by custid order by trxnserno) as rn
From temp_Unpaid1
) rn_qry
ON (temp.custid = rn_qry.custid
AND temp.trxnserno = rn_qry.trxnserno
)
WHEN MATCHED THEN
UPDATE SET
temp.cyclage = rn_qry.rn
;
注意:遗憾的是,我现在无法测试语法的准确性,但希望这具有一定的价值。 :)