14

我想选择几个字段的串联,但它们之间有一个分隔符。仅当两个操作数都不为空时,分隔符才应存在。

因此,对于 的记录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 时。;-)

我找不到更短、更容易或更易读的方法,但我想在完全放弃之前我会在这里问一下(或者自己浪费时间编写这样的函数)。

4

3 回答 3

7

我知道你用的是 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;

现在我不确定这是否比你原来的例子好得多(更具可读性):-)

于 2012-07-12T14:39:59.820 回答
5
select trim(';' from REGEXP_REPLACE (a || ';' || b || ';' || c , ';+' , ';')) abc 
from Table1
于 2019-04-30T10:43:08.133 回答
2

AFAIK,没有简洁的方法可以做到这一点。

过去,我曾求助于

SELECT a
||     DECODE(b
       ,      NULL, NULL
       ,      ';' || b)
||     DECODE(c
       ,      NULL, NULL
       ,      ';' || c)
||     DECODE(d
       ,      NULL, NULL
       ,      ';' || d)
...
FROM   table1

但这并不比你的例子好。

于 2012-07-12T14:39:48.883 回答