SQL Query to concatenate column values from multiple rows in Oracle

前端 未结 10 1252
鱼传尺愫
鱼传尺愫 2020-11-21 07:12

Would it be possible to construct SQL to concatenate column values from multiple rows?

The following is an example:

Table A

PID
A
B
C

相关标签:
10条回答
  • 2020-11-21 07:13

    For those who must solve this problem using Oracle 9i (or earlier), you will probably need to use SYS_CONNECT_BY_PATH, since LISTAGG is not available.

    To answer the OP, the following query will display the PID from Table A and concatenate all the DESC columns from Table B:

    SELECT pid, SUBSTR (MAX (SYS_CONNECT_BY_PATH (description, ', ')), 3) all_descriptions
    FROM (
           SELECT ROW_NUMBER () OVER (PARTITION BY pid ORDER BY pid, seq) rnum, pid, description
           FROM (
                  SELECT a.pid, seq, description
                  FROM table_a a, table_b b
                  WHERE a.pid = b.pid(+)
                 )
          )
    START WITH rnum = 1
    CONNECT BY PRIOR rnum = rnum - 1 AND PRIOR pid = pid
    GROUP BY pid
    ORDER BY pid;
    

    There may also be instances where keys and values are all contained in one table. The following query can be used where there is no Table A, and only Table B exists:

    SELECT pid, SUBSTR (MAX (SYS_CONNECT_BY_PATH (description, ', ')), 3) all_descriptions
    FROM (
           SELECT ROW_NUMBER () OVER (PARTITION BY pid ORDER BY pid, seq) rnum, pid, description
           FROM (
                  SELECT pid, seq, description
                  FROM table_b
                 )
          )
    START WITH rnum = 1
    CONNECT BY PRIOR rnum = rnum - 1 AND PRIOR pid = pid
    GROUP BY pid
    ORDER BY pid;
    

    All values can be reordered as desired. Individual concatenated descriptions can be reordered in the PARTITION BY clause, and the list of PIDs can be reordered in the final ORDER BY clause.


    Alternately: there may be times when you want to concatenate all the values from an entire table into one row.

    The key idea here is using an artificial value for the group of descriptions to be concatenated.

    In the following query, the constant string '1' is used, but any value will work:

    SELECT SUBSTR (MAX (SYS_CONNECT_BY_PATH (description, ', ')), 3) all_descriptions
    FROM (
           SELECT ROW_NUMBER () OVER (PARTITION BY unique_id ORDER BY pid, seq) rnum, description
           FROM (
                  SELECT '1' unique_id, b.pid, b.seq, b.description
                  FROM table_b b
                 )
          )
    START WITH rnum = 1
    CONNECT BY PRIOR rnum = rnum - 1;
    

    Individual concatenated descriptions can be reordered in the PARTITION BY clause.

    Several other answers on this page have also mentioned this extremely helpful reference: https://oracle-base.com/articles/misc/string-aggregation-techniques

    0 讨论(0)
  • 2020-11-21 07:14

    With SQL model clause:

    SQL> select pid
      2       , ltrim(sentence) sentence
      3    from ( select pid
      4                , seq
      5                , sentence
      6             from b
      7            model
      8                  partition by (pid)
      9                  dimension by (seq)
     10                  measures (descr,cast(null as varchar2(100)) as sentence)
     11                  ( sentence[any] order by seq desc
     12                    = descr[cv()] || ' ' || sentence[cv()+1]
     13                  )
     14         )
     15   where seq = 1
     16  /
    
    P SENTENCE
    - ---------------------------------------------------------------------------
    A Have a nice day
    B Nice Work.
    C Yes we can do this work!
    
    3 rows selected.
    

    I wrote about this here. And if you follow the link to the OTN-thread you will find some more, including a performance comparison.

    0 讨论(0)
  • 2020-11-21 07:14
    1. LISTAGG delivers the best performance if sorting is a must(00:00:05.85)

      SELECT pid, LISTAGG(Desc, ' ') WITHIN GROUP (ORDER BY seq) AS description FROM B GROUP BY pid;

    2. COLLECT delivers the best performance if sorting is not needed(00:00:02.90):

      SELECT pid, TO_STRING(CAST(COLLECT(Desc) AS varchar2_ntt)) AS Vals FROM B GROUP BY pid;

    3. COLLECT with ordering is bit slower(00:00:07.08):

      SELECT pid, TO_STRING(CAST(COLLECT(Desc ORDER BY Desc) AS varchar2_ntt)) AS Vals FROM B GROUP BY pid;

    All other techniques were slower.

    0 讨论(0)
  • 2020-11-21 07:20

    Before you run a select query, run this:

    SET SERVEROUT ON SIZE 6000

    SELECT XMLAGG(XMLELEMENT(E,SUPLR_SUPLR_ID||',')).EXTRACT('//text()') "SUPPLIER" 
    FROM SUPPLIERS;
    
    0 讨论(0)
  • 2020-11-21 07:20

    Try this code:

     SELECT XMLAGG(XMLELEMENT(E,fieldname||',')).EXTRACT('//text()') "FieldNames"
        FROM FIELD_MASTER
        WHERE FIELD_ID > 10 AND FIELD_AREA != 'NEBRASKA';
    
    0 讨论(0)
  • 2020-11-21 07:21

    There are a few ways depending on what version you have - see the oracle documentation on string aggregation techniques. A very common one is to use LISTAGG:

    SELECT pid, LISTAGG(Desc, ' ') WITHIN GROUP (ORDER BY seq) AS description
    FROM B GROUP BY pid;
    

    Then join to A to pick out the pids you want.

    Note: Out of the box, LISTAGG only works correctly with VARCHAR2 columns.

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