当某些值可能为null时,逗号分隔多个列

时间:2016-09-19 21:31:32

标签: sql oracle

当每个列都包含NULL值时,我需要用逗号分隔多个列中包含的值:

with

data as (

  select  null a, null b, null c from dual
  union all

  select  'a' a, null b, null c from dual
  union all
  select  null a, 'b' b, null c from dual
  union all
  select  null a, null b, 'c' c from dual

  union all
  select  'a' a, 'b' b, null c from dual
  union all
  select  'a' a, null b, 'c' c from dual

  union all
  select  null a, 'b' b, 'c' c from dual

  union all
  select  'a' a, 'b' b, 'c' c from dual

)

select  a,b,c
        ,case
        when a is not null and b is not null and c is not null then a || ',' || b || ',' ||c
        when a is not null and b is not null then a || ',' || b
        when a is not null and c is not null then a || ',' || c
        when b is not null and c is not null then b || ',' || c
        when a is not null then a
        when b is not null then b
        when c is not null then c
        end abc
from    data

结果:

A   B   C   ABC

a           a
    b       b
        c   c
a   b       a,b
a       c   a,c
    b   c   b,c
a   b   c   a,b,c

是否有一种方法比我abc所做的更简单,最好不必使用PL / SQL?

4 个答案:

答案 0 :(得分:3)

您真正想要的功能是concat_ws(),但Oracle没有。但是这里有一个比你的方法更麻烦的替代方案:

select a, b, c,
       trim(both ',' from replace(replace(a || ',' || b || ',' || c, ',,', ','), ',,', ',')
from data;

这将使用逗号创建字符串。 Oracle忽略字符串连接中的NULL值。然后删除重复的逗号以及前导和尾随逗号。

另一种方法是:

select a, b, c,
       trim(trailing ',' from
            coalesce(a || ',', '') || coalesce(b || ',', '') || coalesce(c || ',', '') 
           )
from data;

我其实更喜欢这个版本。它更具普遍性;中间结果没有一串逗号粘在字符串的中间。

答案 1 :(得分:1)

通过将,连接到列值(a和b)(如果它们非空并且修剪尾随,)来实现此目的。

select a, b, c,
trim(trailing ',' from 
     case when a is null then '' else a||',' end ||
     case when b is null then '' else b||',' end || 
     case when c is null then '' else c end) abc  
from data

Working example

答案 2 :(得分:0)

基于不同版本的TRIM的解决方案应该有效,因为逗号不应该是合法的"数据中的字符。如果是,则应使用其他分隔符。但是,如果您的数据中有逗号,则TRIM解决方案可能会在结果的开头或结尾删除逗号,即使它们是数据的一部分。

您可以使用SUBSTR而不是TRIM来避免这种情况。像

这样的东西
select a, b, c,
       substr(case when a is not null then ',' || a end  ||
              case when b is not null then ',' || b end  ||
              case when c is not null then ',' || c end
             , 2) as abc
from data
;

非常类似于vkp的解决方案,逗号从后面移到前面,这样SUBSTR可以非常简单地编写。对于任何非null值,先添加逗号,然后连接结果。然后SUBSTR读取除第一个字符以外的所有内容(它从字符编号2开始读取),或者如果整个连接为NULL则返回NULL - 完全符合需要。

答案 3 :(得分:0)

这有效:

SELECT  a,b,c
        ,trim(trailing ',' from nvl2(a,a || ',', '') || nvl2(b,b || ',', '') || nvl2(c,c || ',', ''))` abc
FROM    data;

**编辑**

这适用于多字符(逗号空格)分隔符:

SELECT  a,b,c
        ,rtrim( nvl2(a,a || ', ', '') || nvl2(b,b || ', ', '') || nvl2(c,c || ', ', ''), ', ' ) abc
FROM    data;