ORACLE/SQL: wm_concat & order by
Posted
技术标签:
【中文标题】ORACLE/SQL: wm_concat & order by【英文标题】: 【发布时间】:2011-02-11 15:00:33 【问题描述】:我正在通过 ODBC 和水晶报告 2008 使用 oracle 11(不确定确切的版本,但由于 LISTAGG 不起作用,我想它不是版本 2)。
这是我遇到的问题:
这是一张桌子:
TABLE ODB.TASK_CARD_CONTROL
------------------------------------------
task_card control_category code
------------------------------------------
1 zone 17
1 zone 33
1 zone 21
2 zone 18
2 zone 05
3 zone 55
3 zone 32
3 zone 72
我正在使用 WM_CONCAT 函数来获得这样的东西:
task_card zones
1 17,33,21
2 18,05
3 55,32,72
下面是 SQL:
SELECT TASK_CARD, WM_CONCAT(code) as ZONES
FROM ODB.TASK_CARD_CONTROL
WHERE ODB.TASK_CARD_CONTROL.CONTROL_CATEGORY = 'ZONE'
GROUP BY TASK_CARD
但我想对区域进行排序,所以我尝试了这个:
SELECT TASK_CARD, WM_CONCAT(code) as ZONES
FROM (SELECT TASK_CARD, CODE, CONTROL_CATEGORY FROM ODB.TASK_CARD_CONTROL
ORDER BY CODE)
WHERE ODB.TASK_CARD_CONTROL.CONTROL_CATEGORY = 'ZONE'
GROUP BY TASK_CARD
但由于某种原因,它返回以下错误:
Failed to retrieve data from the database.
Details: 42S22:[Oracle][ODBC][Ora]ORA-00904:
"ODB"."TASK_CARD_CONTROL"."CONTROL_CATEGORY" : invalid identifier
我真的不明白我在这里做错了什么......有人可以给我提示吗?
【问题讨论】:
【参考方案1】:对于仍在使用 wm_CONCAT(又名旧 db 版本)的任何人: 解决方案是添加不同的条件,然后它也会对连接的值应用升序。
不要问为什么它没有记录在案,但它会起作用。
另外,在子查询中使用 order by,在 wm_concat 之前只会随机化顺序,所以不应该推荐它。
请求的 SQL 示例:
SELECT TASK_CARD, WM_CONCAT(distinct code) as ZONES
FROM ODB.TASK_CARD_CONTROL
WHERE ODB.TASK_CARD_CONTROL.CONTROL_CATEGORY = 'ZONE'
GROUP BY TASK_CARD;
请注意,在过程/包中使用时 distinct 选项不起作用。
【讨论】:
【参考方案2】:您不能从内部查询外部引用 ODB.TASK_CARD_CONTROL.CONTROL_CATEGORY。试试:
SELECT TASK_CARD, WM_CONCAT(code) as ZONES
FROM (SELECT TASK_CARD, CODE, CONTROL_CATEGORY FROM ODB.TASK_CARD_CONTROL
WHERE ODB.TASK_CARD_CONTROL.CONTROL_CATEGORY = 'ZONE'
ORDER BY CODE)
GROUP BY TASK_CARD
【讨论】:
好吧,我在此期间也想过;我试过这个: SELECT TASK_CARD, WM_CONCAT(code) as ZONES FROM (SELECT TASK_CARD, CODE, FROM ODB.TASK_CARD_CONTROL WHERE ODB.TASK_CARD_CONTROL.CONTROL_CATEGORY = 'ZONE' ORDER BY CODE) GROUP BY TASK_CARD - 但在选择中省略了 CONTROL_CATEGORY给了我一个错误。将其添加回您的查询中,现在似乎可以正常工作了!谢谢:) @LalitKumarB 你为什么问我?我正在回答一个(顺便)使用 WM_CONCAT 的问题,而不是提倡使用它! @LalitKumarB 没问题!【参考方案3】:如果你在 from 子句中给子查询一个名字,你就可以引用子查询本身的列
SELECT t1.TASK_CARD
, WM_CONCAT(t1.code) as ZONES
FROM
(SELECT TASK_CARD, CODE, CONTROL_CATEGORY FROM ODB.TASK_CARD_CONTROL ORDER BY CODE) t1
WHERE t1.CONTROL_CATEGORY = 'ZONE'
GROUP BY t1.TASK_CARD
【讨论】:
即使没有子查询别名,您也可以这样做,因为接受的答案显示【参考方案4】:-
按所需列排序,然后
在外部查询中按行号排序。
使用函数。
这个函数有最后一个rownum顺序的逻辑:
Select wmsys.wm_concat(t) CONCAT from
(
Select t from (
Select t from (
Select 'aa' t from dual
union
Select 'zz' t from dual
union
Select 'pp' t from dual
union
Select 'll' t from dual
union
Select 'mm' t from dual
union
Select 'xx' t from dual
union
Select 'cc' t from dual
) a
order by t
) order by rownum
) t
【讨论】:
【参考方案5】:LISTAGG 是在 11g 第 2 版 中引入的。
因此,在不支持LISTAGG
的11g 之前的Oracle 版本 中,您可以使用ROW_NUMBER() 和SYS_CONNECT_BY_PATH 函数。
见Oracle String Aggregation Techniques
SELECT task_card,
LTRIM(MAX(SYS_CONNECT_BY_PATH(code,','))
KEEP (DENSE_RANK LAST ORDER BY curr),',') AS zones
FROM (SELECT task_card,
code,
ROW_NUMBER() OVER (PARTITION BY fruit ORDER BY code) AS curr,
ROW_NUMBER() OVER (PARTITION BY fruit ORDER BY code) -1 AS prev
FROM table_name)
GROUP BY task_card
CONNECT BY prev = PRIOR curr AND task_card= PRIOR task_card
START WITH curr = 1;
注意
永远不要使用WM_CONCAT
,因为它是一个未记录的功能,并且已从 12c 版本中删除。
任何一直依赖wm_concat
功能的应用程序一旦升级到12c
将无法运行。从那以后,它已被删除。见Why not use WM_CONCAT function in Oracle?
SQL> select banner from v$version where rownum = 1;
BANNER
----------------------------------------------------------------------------
Oracle Database 12c Enterprise Edition Release 12.1.0.1.0 - 64bit Production
SQL> SELECT object_name
2 FROM dba_objects
3 WHERE owner='WMSYS'
4 AND object_name LIKE 'WM\_%' ESCAPE '\';
OBJECT_NAME
----------------------------------------------------------------------------
WM_REPLICATION_INFO
WM_RDIFF
WM_PERIOD
WM_PERIOD
WM_OVERLAPS
WM_MEETS
WM_LESSTHAN
WM_LDIFF
WM_INTERSECTION
WM_INSTALLATION
WM_GREATERTHAN
WM_EVENTS_INFO
WM_ERROR
WM_ERROR
WM_EQUALS
WM_DDL_UTIL
WM_DDL_UTIL
WM_CONTAINS
WM_COMPRESS_BATCH_SIZES
WM_COMPRESSIBLE_TABLES
20 rows selected.
SQL>
您将收到“invalid identifier”错误:
SQL> SELECT banner FROM v$version;
BANNER
----------------------------------------------------------------------------
Oracle Database 12c Enterprise Edition Release 12.1.0.1.0 - 64bit Production
PL/SQL Release 12.1.0.1.0 - Production
CORE 12.1.0.1.0 Production
TNS for 64-bit Windows: Version 12.1.0.1.0 - Production
NLSRTL Version 12.1.0.1.0 - Production
SQL> SELECT deptno, wm_concat(ename) FROM emp;
SELECT deptno, wm_concat(ename) FROM emp
*
ERROR at line 1:
ORA-00904: "WM_CONCAT": invalid identifier
因此,没有必要依赖最新版本中不再提供的未记录的功能。
【讨论】:
【参考方案6】:使用 ListAgg 代替 wm_concat
SELECT TASK_CARD, ListAgg(code) within (order by code asc) as ZONES
http://nimishgarg.blogspot.com/2010/07/oracle-differece-between-wmconcat-and.html
【讨论】:
OP 明确表示不能使用listagg
。另外,它是WITHIN GROUP
。以上是关于ORACLE/SQL: wm_concat & order by的主要内容,如果未能解决你的问题,请参考以下文章