问题
I want to select a concatenation of a couple of fields, but with a separator between them. The separator should only be there if both operands are not null.
So for a record with a='foo', b=NULL, c='bar'
, I want to get the result abc='foo;bar'
(not 'foo;;bar'
).
I would like to have a function like concat_sep(a, b, ';')
that only adds the ';' inbetween if both a and b are not null.
Of course, I can use nvl2 like this:
select
a, b, c,
substr(abc, 1, length(abc) - 1) as abc
from
(select
a, b, c,
nvl2(a, a || ';', '') || nvl2(b, b || ';', '') || nvl2(c, c || ';', '') as abc
from
Table1)
But as you can see, this code becomes cloggy soon, especially when you got more than 3 columns and you've given them sensible names instead of a, b and c. ;-)
I couldn't find a shorter, easier or more readable way, but I thought I'd ask here before giving up entirely (or waste time writing such a function myself).
回答1:
I know you're using 10g, so that won't work. But for completeness, LISTAGG() handles NULL
values "correctly". For that you'd have to update to 11g2, though:
-- Some sample data, roughly equivalent to yours
with t as (
select 'foo' as x from dual union all
select null from dual union all
select 'bar' from dual
)
-- Use the listagg aggregate function to join all values
select listagg(x, ';') within group (order by rownum)
from t;
Or a bit more succinct, if you want to list columns from a table:
-- I use SYS.ORA_MINING_VARCHAR2_NT as a TABLE TYPE. Use your own, if you prefer
select listagg(column_value, ';') within group (order by rownum)
from table(ORA_MINING_VARCHAR2_NT('foo', null, 'bar'));
Or against an actual table:
select listagg(column_value, ';')
within group (order by rownum)
from Table1
cross join table(ORA_MINING_VARCHAR2_NT(Table1.a, Table1.b, Table1.c))
group by Table1.id;
Now I'm not sure if this is so much better (more readable) than your original example :-)
回答2:
AFAIK, there's no succinct way to do this.
In the past, I've resorted to
SELECT a
|| DECODE(b
, NULL, NULL
, ';' || b)
|| DECODE(c
, NULL, NULL
, ';' || c)
|| DECODE(d
, NULL, NULL
, ';' || d)
...
FROM table1
but that's no better than your example.
回答3:
select trim(';' from REGEXP_REPLACE (a || ';' || b || ';' || c , ';+' , ';')) abc
from Table1
来源:https://stackoverflow.com/questions/11454136/oracle-concat-with-delimiter-but-only-if-both-operands-are-not-null