Oracle: Concat с разделителем, но только если оба операнда не являются нулевыми
Я хочу выбрать конкатенацию нескольких полей, но с разделителем между ними. Разделитель должен быть только в том случае, если оба операнда не имеют значения null.
так для записи с a='foo', b=NULL, c='bar'
, Я хочу получить результат abc='foo;bar'
(не 'foo;;bar'
).
Я хотел бы иметь функцию, как concat_sep(a, b, ';')
это добавляет Только"; " между, если оба a и b не являются нулевыми.
конечно, я могу использовать nvl2 следующим образом:
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)
но как вы можете видеть, это код вскоре становится забитым, особенно когда у вас есть более 3 столбцов, и вы дали им разумные имена вместо a, b и C. ; -)
Я не мог найти более короткий, простой или более читаемый способ, но я думал, что спрошу здесь, прежде чем полностью отказаться (или тратить время на написание такой функции самостоятельно).
2 ответов
Я знаю, что вы используете 10g, так что это не сработает. Но для полноты картины,LISTAGG()
ручки NULL
значения "правильно". Для этого вам придется обновить до 11g2, хотя:
-- 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;
или немного более лаконично, если вы хотите перечислить столбцы из таблицы:
-- 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'));
или против фактической таблицы:
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;
теперь я не уверен, что это намного лучше (более четкий), чем ваш исходный пример :-)
AFAIK, нет краткого способа сделать это.
в прошлом я прибегал к
SELECT a
|| DECODE(b
, NULL, NULL
, ';' || b)
|| DECODE(c
, NULL, NULL
, ';' || c)
|| DECODE(d
, NULL, NULL
, ';' || d)
...
FROM table1
но это не лучше, чем ваш пример.