问题描述
考虑这个脚本 (我也把它放在Live SQL:https://livesql.oracle.com/apex/livesql/s/hbfb7x0c47ubwjpygs3klr3wj)
当我运行它,我得到这样的东西:
无论我在inter GROUP (ORDER BY ..) 子句中放入什么,排序都被忽略并且似乎是随机的。这是bug还是已知限制?有变通办法吗?
CREATE TABLE t (
id NUMBER(10) GENERATED ALWAYS AS IDENTITY NOT NULL PRIMARY KEY,
category NUMBER(10) NOT NULL,
counter NUMBER(10),
text VARCHAR2(10) NOT NULL
);
INSERT INTO t (category, text)
SELECT dbms_random.value(1, 10), dbms_random.string('a', 10)
FROM dual
CONNECT BY level <= 100;
DECLARE
v_text VARCHAR2(2000);
v_updated PLS_INTEGER := 0;
BEGIN
UPDATE t
SET counter = nvl(counter, 0) + 1
WHERE category = 1
RETURNING
listagg (text, ', ') WITHIN GROUP (ORDER BY text DESC),
count(*)
INTO
v_text,
v_updated;
COMMIT;
dbms_output.put_line('Rows updated: ' || v_updated);
dbms_output.put_line('Returned: ' || v_text);
END; 当我运行它,我得到这样的东西:
Rows updated: 8 Returned: EHjMWhyYYB, NeXOeOUOtl, eCKQeVNgii, vdfoaOEDbS, WnfPUiTNcZ, ciBYUHUgEe, ccZVEgaVAm, sPyXHepzae
无论我在inter GROUP (ORDER BY ..) 子句中放入什么,排序都被忽略并且似乎是随机的。这是bug还是已知限制?有变通办法吗?
专家解答
我的猜测是一个错误 (我会记录下来)。
只要它被实现了,返回一直是关于简单的表达式或 “简单” 的聚合 (我使用术语 “简单” 没有什么意味着排序),例如,我们不允许在聚合等。
因此,我愿意假设我们从未在返回子句中实现过 * ordering * 操作,而没有意识到LISTAGG是第一个需要聚合和顺序的聚合。
我对您的演示进行了一些修改-看起来就像在表中遇到的那样简单地汇总了,例如
解决方法有点笨拙,因为对行进行排序的责任落在您身上,例如
只要它被实现了,返回一直是关于简单的表达式或 “简单” 的聚合 (我使用术语 “简单” 没有什么意味着排序),例如,我们不允许在聚合等。
因此,我愿意假设我们从未在返回子句中实现过 * ordering * 操作,而没有意识到LISTAGG是第一个需要聚合和顺序的聚合。
我对您的演示进行了一些修改-看起来就像在表中遇到的那样简单地汇总了,例如
SQL> CREATE TABLE t (
2 id NUMBER(10) GENERATED ALWAYS AS IDENTITY NOT NULL PRIMARY KEY,
3 category NUMBER(10) NOT NULL,
4 counter NUMBER(10),
5 text VARCHAR2(10) NOT NULL
6 );
Table created.
SQL>
SQL> INSERT INTO t (category, text)
2 SELECT mod(rownum,3), chr(64+rownum)
3 FROM dual
4 CONNECT BY level <= 10;
10 rows created.
SQL>
SQL> select * from t;
ID CATEGORY COUNTER TEXT
---------- ---------- ---------- ----------
1 1 A
2 2 B
3 0 C
4 1 D
5 2 E
6 0 F
7 1 G
8 2 H
9 0 I
10 1 J
10 rows selected.
SQL>
SQL> set serverout on
SQL> DECLARE
2 v_text VARCHAR2(2000);
3 v_updated PLS_INTEGER := 0;
4 BEGIN
5 UPDATE t
6 SET counter = nvl(counter, 0) + 1
7 WHERE category = 1
8 RETURNING
9 listagg (text, ', ') WITHIN GROUP (ORDER BY text ),
10 count(*)
11 INTO
12 v_text,
13 v_updated;
14
15 COMMIT;
16 dbms_output.put_line('Rows updated: ' || v_updated);
17 dbms_output.put_line('Returned: ' || v_text);
18 END;
19 /
Rows updated: 4
Returned: A, D, G, J
PL/SQL procedure successfully completed.
SQL>
SQL> delete t;
10 rows deleted.
SQL> INSERT INTO t (category, text)
2 SELECT mod(rownum,3), chr(64+rownum)
3 FROM dual
4 CONNECT BY level <= 10
5 order by 2 desc; <====== changed order
10 rows created.
SQL>
SQL> select * from t;
ID CATEGORY COUNTER TEXT
---------- ---------- ---------- ----------
11 1 J
12 0 I
13 2 H
14 1 G
15 0 F
16 2 E
17 1 D
18 0 C
19 2 B
20 1 A
10 rows selected.
SQL>
SQL> set serverout on
SQL> DECLARE
2 v_text VARCHAR2(2000);
3 v_updated PLS_INTEGER := 0;
4 BEGIN
5 UPDATE t
6 SET counter = nvl(counter, 0) + 1
7 WHERE category = 1
8 RETURNING
9 listagg (text, ', ') WITHIN GROUP (ORDER BY text ),
10 count(*)
11 INTO
12 v_text,
13 v_updated;
14
15 COMMIT;
16 dbms_output.put_line('Rows updated: ' || v_updated);
17 dbms_output.put_line('Returned: ' || v_text);
18 END;
19 /
Rows updated: 4
Returned: J, G, D, A
PL/SQL procedure successfully completed.
解决方法有点笨拙,因为对行进行排序的责任落在您身上,例如
SQL> delete t;
10 rows deleted.
SQL> INSERT INTO t (category, text)
2 SELECT mod(rownum,3), chr(64+rownum)
3 FROM dual
4 CONNECT BY level <= 10
5 order by 2 desc;
10 rows created.
SQL>
SQL> select * from t;
ID CATEGORY COUNTER TEXT
---------- ---------- ---------- ----------
31 1 J
32 0 I
33 2 H
34 1 G
35 0 F
36 2 E
37 1 D
38 0 C
39 2 B
40 1 A
10 rows selected.
SQL>
SQL> set serverout on
SQL> DECLARE
2 v_text VARCHAR2(2000);
3 v_updated PLS_INTEGER := 0;
4
5 l_list sys.odcivarchar2list := sys.odcivarchar2list();
6 BEGIN
7 UPDATE t
8 SET counter = nvl(counter, 0) + 1
9 WHERE category = 1
10 RETURNING text bulk collect into l_list;
11
12 select listagg(column_value,',') within group ( order by column_value)
13 into v_text
14 from table(l_list);
15
16 COMMIT;
17 dbms_output.put_line('Rows updated: ' || l_list.count);
18 dbms_output.put_line('Returned: ' || v_text);
19 END;
20 /
Rows updated: 4
Returned: A,D,G,J
PL/SQL procedure successfully completed.
「喜欢这篇文章,您的关注和赞赏是给作者最好的鼓励」
关注作者
【版权声明】本文为墨天轮用户原创内容,转载时必须标注文章的来源(墨天轮),文章链接,文章作者等基本信息,否则作者和墨天轮有权追究责任。如果您发现墨天轮中有涉嫌抄袭或者侵权的内容,欢迎发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。




