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
Table B
PID SEQ Desc A 1 Have A 2 a nice A 3 day. B 1 Nice Work. C 1 Yes C 2 we can C 3 do C 4 this work!
Output of the SQL should be -
PID Desc A Have a nice day. B Nice Work. C Yes we can do this work!
So basically the Desc column for out put table is a concatenation of the SEQ values from Table B?
Any help with the SQL?
As most of the answers suggest,
LISTAGG
is the obvious option. However, one annoying aspect withLISTAGG
is that if the total length of concatenated string exceeds 4000 characters( limit forVARCHAR2
in SQL ), the below error is thrown, which is difficult to manage in Oracle versions upto 12.1A new feature added in 12cR2 is the
ON OVERFLOW
clause ofLISTAGG
. The query including this clause would look like:The above will restrict the output to 4000 characters but will not throw the
ORA-01489
error.These are some of the additional options of
ON OVERFLOW
clause:ON OVERFLOW TRUNCATE 'Contd..'
: This will display'Contd..'
at the end of string (Default is...
)ON OVERFLOW TRUNCATE ''
: This will display the 4000 characters without any terminating string.ON OVERFLOW TRUNCATE WITH COUNT
: This will display the total number of characters at the end after the terminating characters. Eg:- '...(5512)
'ON OVERFLOW ERROR
: If you expect theLISTAGG
to fail with theORA-01489
error ( Which is default anyway ).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;
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;
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.
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
:Then join to
A
to pick out thepids
you want.Note: Out of the box,
LISTAGG
only works correctly withVARCHAR2
columns.Before you run a select query, run this:
SET SERVEROUT ON SIZE 6000
There's also an
XMLAGG
function, which works on versions prior to 11.2. BecauseWM_CONCAT
is undocumented and unsupported by Oracle, it's recommended not to use it in production system.With
XMLAGG
you can do the following:What this does is
ename
column (concatenated with a comma) from theemployee_names
table in an xml element (with tag E)The LISTAGG analytic function was introduced in Oracle 11g Release 2, making it very easy to aggregate strings. If you are using 11g Release 2 you should use this function for string aggregation. Please refer below url for more information about string concatenation.
http://www.oracle-base.com/articles/misc/StringAggregationTechniques.php
String Concatenation