14

いくつかのフィールドの連結を選択したいのですが、それらの間にセパレーターがあります。セパレータは、両方のオペランドが null でない場合にのみ存在する必要があります。

したがって、 のレコードa='foo', b=NULL, c='bar'の場合、結果を取得したいabc='foo;bar'( ではありません'foo;;bar')。

concat_sep(a, b, ';')「;」のみを追加するような関数が必要です a と b の両方が null でない場合は、中間。

もちろん、次のように 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 に答える
2

私の知る限り、これを行うための簡潔な方法はありません。

過去に、私は頼りにしました

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 に答える