Ordering the strings while concatenating in oracle

2019-02-28 16:34发布

I am using the collect function to concatenate strings for a sql query.

    select id,
    tab_to_string(CAST(COLLECT(a.level||' '||d.Number||':  
    '||to_char(nvl(de.eventDate,SYSDATE - 365 * 100))) AS t_varchar2_tab)) AS MyVar
    from Mytable
    groupby id

The output of this query is like:

    Id    Myvar
    1     level : 27-Jan-09,level : 27-Mar-08, level : 2-Apr-10
    2     level : 7-Jun-06,level : 27-Dec-08, level : 2-Nov-08
    3     level : 27-July-10,level : 27-Mar-06, level : 2-Apr-10

But i want the "Myvar" value to be ordered by the date field within the concatenated string

so for the Id = 1, the output should be like

    level : 27-Mar-08, level : 27-Jan-09, level : 2-Apr-10

Below is the code for tab_to_string function

source: http://www.oracle-base.com/articles/misc/string-aggregation-techniques.php#wm_concat

    CREATE OR REPLACE FUNCTION tab_to_string (p_varchar2_tab  IN  t_varchar2_tab,
                                      p_delimiter     IN  VARCHAR2 DEFAULT ',') 
    RETURN VARCHAR2 IS
    l_string     VARCHAR2(32767);
    BEGIN
    FOR i IN p_varchar2_tab.FIRST .. p_varchar2_tab.LAST LOOP
    IF i != p_varchar2_tab.FIRST THEN
    l_string := l_string || p_delimiter;
    END IF;
    l_string := l_string || p_varchar2_tab(i);
    END LOOP;
    RETURN l_string;
    END tab_to_string;

I am using Oracle 10g.

Thanks Prash

1条回答
不美不萌又怎样
2楼-- · 2019-02-28 16:53

to get an ordered list, there's a few ways. the simplest is :

select id, str
  from (select id, 
               wm_concat('level : ' || to_char(nvl(eventDate,SYSDATE - 365 * 100))) 
                 over (partition by id order by eventdate) str,
               row_number() over (partition by id order by eventdate desc) rn
         from Mytable)
 where rn = 1;

or if you're using the "stragg" user defined aggregate:

  select id, str
  from (select id, 
               string_agg('level : ' || to_char(nvl(eventDate,SYSDATE - 365 * 100))) 
                 over (partition by id order by eventdate) str,
               row_number() over (partition by id order by eventdate desc) rn
         from Mytable)
 where rn = 1;

eg

SQL> select id, str
  2    from (select id,
  3                 string_agg('level : ' || to_char(nvl(eventDate,SYSDATE - 365 * 100)))
  4                   over (partition by id order by eventdate) str,
  5                 row_number() over (partition by id order by eventdate desc) rn
  6           from Mytable)
  7   where rn = 1;

        ID STR
---------- ----------------------------------------------------------------------
         1 level : 27-MAR-08,level : 27-JAN-09,level : 02-APR-10
         2 level : 07-JUN-06,level : 02-NOV-08,level : 27-DEC-08
         3 level : 27-MAR-06,level : 02-APR-10,level : 27-JUL-10
查看更多
登录 后发表回答