合并Oracle中具有不同值的列

时间:2018-06-27 09:37:23

标签: sql oracle

需要帮助以不同的值合并Oracle中的列。

我有一个名为TEST的表,其中包含以下数据。

ID  ID1   ID2   ID3
1   A     B     C
1   B     P     A
2   X     Y     Z
2   Y     Z     K

需要输出如下

ID  MergedValues
1   A;B;C;P
2   X;Y;Z;K

3 个答案:

答案 0 :(得分:4)

此解决方案已结束:

SELECT id, listagg(v, ';') WITHIN GROUP (ORDER BY v) AS MergedValues
FROM (
  SELECT id, id1 AS v
  FROM test
  UNION 
  SELECT id, id2 AS v
  FROM test
  UNION
  SELECT id, id3 AS v
  FROM test
) t
GROUP BY id

SQLFiddle

它似乎不像您隐式请求的那样保留MergedValues的遇到顺序,而是产生以下内容:

| ID | MERGEDVALUES |
|----|--------------|
|  1 |      A;B;C;P |
|  2 |      K;X;Y;Z |

答案 1 :(得分:4)

您可以将列取消旋转为行,并找到不同的值以删除重复项:

StatelessWidget

然后将select distinct id, val from test unpivot (val for pos in (id1 as 1, id2 as 2, id3 as 3)); 应用于此:

listagg()

将您的示例数据作为CTE:

select id,
  listagg(val, ';') within group (order by val) as mergedvalues
from (
  select distinct id, val
  from test
  unpivot (val for pos in (id1 as 1, id2 as 2, id3 as 3))
)
group by id
order by id;

如果列表中的顺序需要与您显示的顺序匹配,那么似乎几乎是基于显示该值的第一列,因此您可以执行以下操作:

with test (ID, ID1, ID2, ID3) as (
            select 1, 'A', 'B', 'C' from dual
  union all select 1, 'B', 'P', 'A' from dual
  union all select 2, 'X', 'Y', 'Z' from dual
  union all select 2, 'Y', 'Z', 'K' from dual
)
select id,
  listagg(val, ';') within group (order by val) as mergedvalues
from (
  select distinct id, val
  from test
  unpivot (val for pos in (id1 as 1, id2 as 2, id3 as 3))
)
group by id
order by id;

        ID MERGEDVALUES                  
---------- ------------------------------
         1 A;B;C;P                       
         2 K;X;Y;Z                       

更接近,但C和P颠倒了;尚不清楚应该控制什么。也许还有另一列未显示,这意味着行顺序。

答案 2 :(得分:2)

这是我的方法: (注意:发布后,我发现这类似于Alex Poole的方法,只是我先对输入行进行排序。)

  1. 对每个ID中的输入行进行排序:您不说如何,我按ID1,ID2,ID3进行排序
  2. 取消数据透视,为列分配1到3之间的数字
  3. 根据行顺序然后按列顺序为每个值分配优先级
  4. 当一个值出现多次时,仅保留最小的“优先级”
  5. 使用LISTAGG,按优先级排序。
    with data_with_rn as (
      select t.*,
      row_number() over(partition by id order by ID1,ID2,ID3) rn
      from t
    )
    , unpivoted as (
      select id, val,
      row_number() over(partition by id order by rn, col) priority
      from data_with_rn
      unpivot(val for col in(ID1 as 1, ID2 as 2, ID3 as 3))
    )
    , grouped as (
      select id, val, min(priority) priority
      from unpivoted
      group by id, val
    )
    select id, listagg(val, ';') within group(order by priority) vals 
    from grouped
    group by id
    order by id;

ID  VALS
--  --------
1   A;B;C;P
2   X;Y;Z;K