English 中文(简体)
ORACLE/SQL:wm_concat排序依据(&S)
原标题:ORACLE/SQL: wm_concat & order by

我正在通过ODBC和crystal reports 2008使用Oracle11(不确定确切的版本,但由于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

我真的不明白我在这里做错了什么。。。有人能给我一个提示吗?

最佳回答

不能从内部查询外部引用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
问题回答

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.

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

此外,在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;

请注意,在程序/包中使用不同选项时不起作用。

如果给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
  1. Order by the desired column, then
  2. Order in external query order by row number.
  3. Use the function.

此函数具有最后一个行号顺序的逻辑:

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

LISTAGG是在11g Release 2中引入的。

因此,在11g之前的Oracle版本中,LISTAGG不受支持,可以使用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而不是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





相关问题
Export tables from SQL Server to be imported to Oracle 10g

I m trying to export some tables from SQL Server 2005 and then create those tables and populate them in Oracle. I have about 10 tables, varying from 4 columns up to 25. I m not using any constraints/...

Connecting to Oracle 10g with ODBC from Excel VBA

The following code works. the connection opens fine but recordset.recordCount always returns -1 when there is data in the table. ANd If I try to call any methods/properties on recordset it crashes ...

How to make a one to one left outer join?

I was wondering, is there a way to make a kind of one to one left outer join: I need a join that matches say table A with table B, for each record on table A it must search for its pair on table B, ...

Insert if not exists Oracle

I need to be able to run an Oracle query which goes to insert a number of rows, but it also checks to see if a primary key exists and if it does, then it skips that insert. Something like: INSERT ALL ...

How can I store NULLs in NOT NULL field?

I just came across NULL values in NOT-NULL fields in our test database. How could they get there? I know that NOT-NULL constraints can be altered with NOVALIDATE clause, but that would change table s ...

Type reference scope

I m studying databases and am currently working on a object-relational DB project and I ve encountered a small problem with the number of possible constraints in an object table. I m using "Database ...

OracleParameter and DBNull.Value

we have a table in an Oracle Database which contains a column with the type Char(3 Byte). Now we use a parameterized sql to select some rows with a DBNull.Value and it doesn t work: OracleCommand ...

热门标签