Lei*_*fel 6 oracle oracle-11g-r2 gaps-and-islands
用户有一个他们想要更新的表。根据其他列中的数据,他们希望使用从 1 开始的无间隙升序值更新特定列。不包含此升序值的行也需要更新。有没有办法用一个 UPDATE 语句来做到这一点?
创建示例数据:
CREATE TABLE t1 AS (
SELECT CHR(ASCII('a')+rownum-1) letter, rownum Number1, 0 Number2
FROM dual connect by rownum<=7);
Run Code Online (Sandbox Code Playgroud)
分配升序 rownum 的更新语句,但它不是无间隙的:
UPDATE t1 SET Letter=’x’,
Number2 = DECODE(letter,’a’,rownum,’d’,rownum,’e’,rownum,NULL);
Run Code Online (Sandbox Code Playgroud)
使用序列返回相同的结果:
CREATE SEQUENCE s1;
UPDATE t1 SET letter=’x’,
number2 = DECODE(letter,’a’,s1.nextval,’d’, s1.nextval,’e’, s1.nextval,NULL);
Run Code Online (Sandbox Code Playgroud)
完成后,数据应如下所示:
L NUMBER1 NUMBER2
- ---------- ----------
x 1 1
x 2
x 3
x 4 2
x 5 3
x 6
x 7
Run Code Online (Sandbox Code Playgroud)
我不是在寻找仅适用于我的特定测试用例的技巧,而是寻找问题的通用解决方案。
请参阅AskTom 上有关表达式计算方式的讨论。decode
在大多数情况下,该函数确实会执行短路:如果左侧的条件被评估为 ,则不会评估右侧的表达式true
。然而,序列是特殊的,它们在所有情况下都针对所有行进行评估。
最简单的解决方法是使用调用序列的函数:
SQL> CREATE SEQUENCE seq;
Sequence created
SQL> CREATE OR REPLACE FUNCTION f RETURN NUMBER
2 AS
3 l_result NUMBER;
4 BEGIN
5 SELECT seq.nextval INTO l_result FROM dual;
6 RETURN l_result;
7 END;
8 /
Function created
SQL> UPDATE t1 SET letter='x',
2 number2 = DECODE(letter,'a',f,'d', f,'e', f,NULL);
7 rows updated
SQL> select * from t1;
LETTER NUMBER1 NUMBER2
------ ---------- ----------
x 1 1
x 2
x 3
x 4 2
x 5 3
x 6
x 7
7 rows selected
Run Code Online (Sandbox Code Playgroud)
如您所见,该函数仅在 DECODE 表达式需要时才进行计算。
在大多数情况下,您可以使用纯 SQL 解决方案。如果我们假设该表具有 PK(我将采用number1
),则此自联接 SQL 解决方案将起作用:
SQL> UPDATE t1 t1_out
2 SET letter = 'x',
3 number2 = CASE WHEN letter IN ('a', 'd', 'e') --
4 THEN (SELECT COUNT(*)
5 FROM t1 t1_in
6 WHERE letter IN ('a', 'd', 'e')
7 AND t1_in.number1 <= t1_out.number1)
8 END;
7 rows updated
SQL> select * from t1;
LETTER NUMBER1 NUMBER2
------ ---------- ----------
x 1 1
x 2
x 3
x 4 2
x 5 3
x 6
x 7
7 rows selected
Run Code Online (Sandbox Code Playgroud)
您可能已经尝试过分析解决方案。可以编写一个返回适当结果集的查询,但更新和分析不能很好地协同工作(分析往往会产生不可更新的视图)。
归档时间: |
|
查看次数: |
2414 次 |
最近记录: |