我想选择几个字段的串联,但在它们之间有一个分隔符。只有当两个操作数都不为空时,才应该存在分隔符。
因此,对于a='foo', b=NULL, c='bar'
的记录,我希望得到结果abc='foo;bar'
(不是'foo;;bar'
)。
我希望有一个像concat_sep(a, b, ';')
这样的函数只添加';'如果a和b都不为空,则为inbetween。
当然,我可以像这样使用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。 ; - )
我找不到更短,更容易或更易阅读的方式,但我想在完全放弃之前我会问这里(或者浪费时间自己写这样的功能)。
答案 0 :(得分:6)
我知道你使用的是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;
现在我不确定这是否比原始示例更好(更易读): - )
答案 1 :(得分:1)
AFAIK,没有简明扼要的方法。
过去,我已经诉诸
SELECT a
|| DECODE(b
, NULL, NULL
, ';' || b)
|| DECODE(c
, NULL, NULL
, ';' || c)
|| DECODE(d
, NULL, NULL
, ';' || d)
...
FROM table1
但这并不比你的榜样好。
答案 2 :(得分:0)
select trim(';' from REGEXP_REPLACE (a || ';' || b || ';' || c , ';+' , ';')) abc
from Table1