ORACLE/SQL:wm_concat &订购依据

发布于 2024-10-16 18:04:54 字数 1484 浏览 4 评论 0原文

我正在通过 ODBC 和 crystal reports 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

我真的不明白我在这里做错了什么...任何人都可以给我提示吗?

I'm using oracle 11 (not sure about the exact version, but since LISTAGG doesn't work, I suppose it's not release 2) through ODBC and crystal reports 2008.

Here is the problem I have:

Here's a table:

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 

I'm using the WM_CONCAT function to obtain something like this:

task_card      zones
1              17,33,21
2              18,05
3              55,32,72

Here is the SQL for that:

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

but I'd like the zones to be sorted, so I tried this:

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

but for some reason, it returns the following error:

Failed to retrieve data from the database.
Details: 42S22:[Oracle][ODBC][Ora]ORA-00904: 
"ODB"."TASK_CARD_CONTROL"."CONTROL_CATEGORY" : invalid identifier

I really don't understand what I'm doing wrong here... Can anybody give me a hint ?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(6

傾旎 2024-10-23 18:04:54

对于仍在使用 wm_CONCAT (又名旧数据库版本)的任何人:
解决方案是添加不同的条件,然后它还将对连接的值应用升序。

不要问为什么它没有记录,但它会起作用。

另外,在 wm_concat 之前的子查询中使用 order by 只会随机化顺序,因此不建议这样做。

请求的 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;

请注意,在 procedure/packages 中使用时,distinct 选项不起作用。

For anyone that is still using wm_CONCAT (a.k.a. older db versions):
The solution is to add distinct condition, it will then also apply ascending order to the concatenated values.

Don't ask why it's not documented, but it will work.

Also, using a order by in a subquery, previous to wm_concat will just randomize the order, so it shouldn't have been recommended.

Example for the requested 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;

Just be warned that the distinct option does not work when used in procedures/packages .

ぃ双果 2024-10-23 18:04:54

您无法从内部查询外部引用 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

You can't reference ODB.TASK_CARD_CONTROL.CONTROL_CATEGORY from outside the inner query. Try:

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
久夏青 2024-10-23 18:04:54

如果您在 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

If you give the sub query in the from clause a name you can then refer to columns in the sub query itself

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
っ左 2024-10-23 18:04:54
  1. 按所需列排序,然后
  2. 按行号在外部查询中排序。
  3. 使用该功能。

该函数具有最后 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
  1. Order by the desired column, then
  2. Order in external query order by row number.
  3. Use the function.

This function has logic for the last rownum order:

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
≈。彩虹 2024-10-23 18:04:54

LISTAGG 是在 11g 第 2 版 中引入的。

因此,在 11g 之前 不支持 LISTAGG 的 Oracle 版本中,您可以使用 ROW_NUMBER()SYS_CONNECT_BY_PATH功能。

请参阅Oracle 字符串聚合技术

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后将无法工作。从那时起,它已被删除。请参阅 为什么不在 Oracle 中使用 WM_CONCAT 函数?

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>

您将收到“无效标识符”错误:

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

因此,依赖未记录的功能是没有意义的,该功能在最新版本中不再提供。

LISTAGG was introduced in 11g Release 2.

Therefore, in Oracle version prior to 11g where LISTAGG is not supported, you could use ROW_NUMBER() and SYS_CONNECT_BY_PATH functions.

See 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;

NOTE

Never use WM_CONCAT since it is an undocumented feature and it has been removed from 12c version.

Any application which has had been relying on wm_concat function will not work once upgraded to 12c. Since, it has been removed. See 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>

You will receive an “invalid identifier” error:

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

Therefore, there is no point relying on an undocumented feature which is no more made available in latest versions.

爱本泡沫多脆弱 2024-10-23 18:04:54

使用 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

Use ListAgg instead of 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

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文