Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Oracle: Concat with delimiter, but only if both operands are NOT NULL

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).

like image 945
GolezTrol Avatar asked Jul 12 '12 14:07

GolezTrol


People also ask

What is the difference between concat function and || operator?

CONCAT() is an ANSI defined standard function, while the || operator is an Oracle thing (other databases use or &). To conform to standard, CONCAT requires string parameters. Oracle, in their implementation of || will implicity convert other data types to strings.

What is the use of || in Oracle?

The Oracle/PLSQL || operator allows you to concatenate 2 or more strings together.

What is coalesce in Oracle SQL?

COALESCE returns the first non-null expr in the expression list. At least one expr must not be the literal NULL . If all occurrences of expr evaluate to null, then the function returns null. Oracle Database uses short-circuit evaluation.

What does (+) mean in Oracle?

The plus sign is Oracle syntax for an outer join. There isn't a minus operator for joins. An outer join means return all rows from one table. Also return the rows from the outer joined where there's a match on the join key. If there's no matching row, return null.


1 Answers

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 :-)

like image 92
Lukas Eder Avatar answered Nov 16 '22 11:11

Lukas Eder