ORACLE/SQL: wm_concat & order by

前端 未结 6 918
梦如初夏
梦如初夏 2020-12-19 18:17

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

相关标签:
6条回答
  • 2020-12-19 18:52

    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
    
    0 讨论(0)
  • 2020-12-19 18:53
    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
    
    0 讨论(0)
  • 2020-12-19 19:04

    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

    0 讨论(0)
  • 2020-12-19 19:17

    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
    
    0 讨论(0)
  • 2020-12-19 19:17

    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 .

    0 讨论(0)
  • 2020-12-19 19:17

    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.

    0 讨论(0)
提交回复
热议问题