4

This is a sample table data

Fruit   Number
Apple    1
Apple    2
Apple    3
Kiwi     6
Kiwi     10

I try to concatenate the table column values to get the following

Fruit   Number
Apple    1-2-3
Kiwi     6-10

Is there a way to query this or store procedure? Something like Concatenate over(partition by) , I don't know much about stored procedures. Thanks!

Lalit Kumar B
  • 47,486
  • 13
  • 97
  • 124
Sailormoon
  • 259
  • 1
  • 5
  • 23

2 Answers2

6

You don't need a stored procedure for that. Use listagg function:

select fruit, listagg(number, ',') within group (order by number)
from mytable
group by fruit

If your database version is 10g it is still simple: use WM_CONCAT (if doesn't recognize the name probably try WMSYS.WM_CONCAT) function, see example in this answer. Just in case you need to use separator which is different from ,, you can wrap the result in replace function; if you want to order the result just pre-order it in a subquery, e.g.:

select fruit, replace(wm_concat(number), ',', '-')
from (select fruit, number
      from mytable
      order by number)
group by fruit

If you for some mysterious reason don't have the function in your instance you can use a polyfill, see my answer here.

Community
  • 1
  • 1
smnbbrv
  • 23,502
  • 9
  • 78
  • 109
  • Unfortunately, OP is on `10g`, and `LISTAGG` is not supported as it was was introduced in `11gR2`. An alternate solution in 10g is, `ROW_NUMBER()` and `SYS_CONNECT_BY_PATH` functions. – Lalit Kumar B Sep 11 '15 at 14:02
  • @LalitKumarB this is also possible with `wm_concat` function without making unnecessary recursive queries. See e.g. this answer http://stackoverflow.com/a/4970624/1990451 – smnbbrv Sep 11 '15 at 14:48
  • Never use **`WM_CONCAT`**, as it is an **undocumented feature** and it is completely **removed in Oracle 12c**. Don't just rely on other's answers, but please spend sometime to learn and understand the facts. See [Why not use WM_CONCAT function in Oracle?](http://lalitkumarb.com/2015/04/29/why-not-use-wm_concat-function-in-oracle/) – Lalit Kumar B Sep 11 '15 at 15:46
  • @LalitKumarB the fact that it works in 10-11 versions still means it works and it can be a solution. If you have read more carefully there is also provided a way how to make a custom analytic function `wm_concat` which would be acceptable for 12c. So I rely on **facts** and on **my** answers, and I really spend lots of time to learn and understand facts, although guys like you cannot even read the post till the end before starting commenting – smnbbrv Sep 12 '15 at 20:57
  • *the fact that it works in 10-11 versions still means it works* - No point in explaining to you further. If you are advocating the use of an undocumented feature, then you are on your own. – Lalit Kumar B Sep 13 '15 at 07:26
1

OP is on Oracle 10g, and 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.

SELECT fruit,
  LTRIM(MAX(SYS_CONNECT_BY_PATH(number,','))
  KEEP (DENSE_RANK LAST ORDER BY curr),',') AS fruits_agg
  FROM   (SELECT fruit,
                number,
                ROW_NUMBER() OVER (PARTITION BY fruit ORDER BY number) AS curr,
                ROW_NUMBER() OVER (PARTITION BY fruit ORDER BY number) -1 AS prev
         FROM   table_name)
  GROUP BY fruit
  CONNECT BY prev = PRIOR curr AND fruit = PRIOR fruit
 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.

Lalit Kumar B
  • 47,486
  • 13
  • 97
  • 124
  • _Never use WM_CONCAT_ - why not? You can always add it back in 12c, if you have a look e.g. [here](http://stackoverflow.com/a/22145391/1990451) (that is btw pointed in my answer too). – smnbbrv Sep 12 '15 at 20:54
  • @smnbbrv Perhaps you don't care about your database and need of Oracle support. When it is said that a feature is *not documented*, it means if something goes wrong then you are on your own. And how do you handle such things in your production environment? Or do you just not care? – Lalit Kumar B Sep 13 '15 at 07:23
  • When you have a problem you first come to the StackOverflow and you are not alone here. My live systems are up and always running and funny to say but Oracle support never helped me probably because they are showing off only like you do. You believe you are right but the fact that my answer is accepted by 5 persons and yours by one only, says that probably this is not true. Your behaviour here makes me think one more time before I will ever mind to go to the Oracle support again – smnbbrv Sep 13 '15 at 07:37
  • @smnbbrv Every industry using Oracle database buys a license and pays for the support. I haven't seen a single production system running without a license and support. And yes I can see very well people voted your answer, when you mentioned LISTAGG which was good and I appreciated too by voting up. But suggesting wm_concat is not good, and I just explained why as it is not an industry standard. Imagine someone upgrading from 10g to 11g and finds the feature is unavailable. – Lalit Kumar B Sep 13 '15 at 12:36
  • You would argue you will write a user defined function. But why? Inbuilt functions are faster than user defined functions. You would have to rewrite the code to use the new LISTAGG. There are multiple options for string aggregation, out of which wm_concat which is provided in the work space manager, is not recommended by Oracle. You can go on arguing about doing things in PL/SQL, of course, you could do anything programmatically. But, if you can do it in pure SQL, no need to use PL/SQL. – Lalit Kumar B Sep 13 '15 at 12:37
  • @LalitKumarB if I have a third column called date how do I use that as a identifier besides fruit? Thanks Lalit I can make another post regarding this question, I'm confused by how to to use system connect by path. – Sailormoon Oct 29 '15 at 14:36
  • @LalitKumarB http://stackoverflow.com/questions/33417399/string-aggregation-in-oracle-10g-with-three-columns – Sailormoon Oct 29 '15 at 14:46
  • @sailormoon It is simple, just put the first two columns in partition by clause and group by clause. – Lalit Kumar B Oct 29 '15 at 16:35