Concat distinct value in oracle sql 在Oracle SQL中连接不同的值

huangapple go评论58阅读模式
英文:

Concat distinct value in oracle sql

问题

You can achieve the desired output in Oracle SQL by using the DISTINCT keyword within the CONCAT function to remove duplicates. Here's the modified query:

SELECT user, 
       RTRIM(XMLAGG(XMLELEMENT(E, acc || ',')).EXTRACT('//text()'), ',') AS acc
FROM (
  SELECT user, acc_1 AS acc FROM myTable WHERE acc_1 IS NOT NULL
  UNION ALL
  SELECT user, acc_2 AS acc FROM myTable WHERE acc_2 IS NOT NULL
  UNION ALL
  SELECT user, acc_3 AS acc FROM myTable WHERE acc_3 IS NOT NULL
  UNION ALL
  SELECT user, acc_4 AS acc FROM myTable WHERE acc_4 IS NOT NULL
) 
GROUP BY user;

This query combines values from acc_1, acc_2, acc_3, and acc_4 into a single column acc, removes duplicates, and produces the desired output.

英文:

How can I concat distinct value in oracle sql?

My table structure look like following:

user acc_1 acc_2 acc_3 acc_4
1 t1 t1
2 t2 t2 t2
3 t3
create table myTable (user, acc_1, acc_2,acc_3,acc_4) as
 select   1, t1, t1, null,null from dual union all
select   2, t2, null, t2,t2  from dual union all
select   3, null, t3, null,null  from dual ;

when I run the query:

select user, acc_1 || ','||acc_2||','||acc_3||','||acc_4 as acc
from myTable

I get output as:

user acc
1 t1 , t1 ,,
2 t2 ,, t2,t2
3 , t3,,

But I don't need duplicate of acc.
I need my output as:

user acc
1 t1
2 t2
3 t3

Is this possible?

答案1

得分: 3

以下是您要翻译的内容:

最简单的方法是“unpivot”您的数据,将其视为行。
例如:

with unpivot_data as (
select user_, acc_1 acc from myTable where acc_1  is not null
union all
select user_, acc_2 from myTable where acc_2 is not null
union all
select user_, acc_3 from myTable where acc_3 is not null
union all
select user_, acc_4 from myTable where acc_4 is not null
  )
select user_, listagg(distinct acc, ', ') 
  from unpivot_data
 group by user_

在这里,我将您的数据转换为行,并使用LISTAGG(DISTINCT ...)将它们连接起来,如描述的那样。

演示在这里

显然,您也可以在这里使用UNPIVOT

编辑: 正如@Littlefoot正确指出的,建议的解决方案对于较旧版本的Oracle将无法工作。对于它们,可以使用UNION代替UNION ALL并在聚合函数中省略DISTINCT

with unpivot_data as (
select user_, acc_1 acc from myTable where acc_1  is not null
union 
select user_, acc_2 from myTable where acc_2 is not null
union 
select user_, acc_3 from myTable where acc_3 is not null
union 
select user_, acc_4 from myTable where acc_4 is not null
  )
select user_, listagg(acc, ', ')  WITHIN GROUP (order by acc)
  from unpivot_data
 group by user_
英文:

Easiest way would be "unpivot" your data, and treat it as row for this.
For example:

with unpivot_data as (
select user_, acc_1 acc from myTable where acc_1  is not null
union all
select user_, acc_2 from myTable where acc_2 is not null
union all
select user_, acc_3 from myTable where acc_3 is not null
union all
select user_, acc_4 from myTable where acc_4 is not null
  )
select user_, listagg(distinct acc, ', ') 
  from unpivot_data
 group by user_

Here I converted your data to rows, and used LISTAGG(DISTINCT ...) to join them as described.

Demo here.

Obviously you can also use UNPIVOT here too.

EDIT: as @Littlefoot correctly pointed out suggested solution will not work for older versions of Oracle. For them it is possible to use UNION instead of UNION ALL and skip DISTINCT in aggregation function.

with unpivot_data as (
select user_, acc_1 acc from myTable where acc_1  is not null
union 
select user_, acc_2 from myTable where acc_2 is not null
union 
select user_, acc_3 from myTable where acc_3 is not null
union 
select user_, acc_4 from myTable where acc_4 is not null
  )
select user_, listagg(acc, ', ')  WITHIN GROUP (order by acc)
  from unpivot_data
 group by user_

答案2

得分: 2

以下是翻译好的部分:

给定示例数据:

create table myTable ("USER", acc_1, acc_2,acc_3,acc_4) as
select 1, 't1', 't1', null, null from dual union all
select 2, 't2', null, 't2', 't2' from dual union all
select 3, null, 't3', null, null from dual;

您可以使用CASE表达式(虽然需要键入更多,但只需要单个表扫描并使用简单快速的比较):

SELECT "USER",
          CASE WHEN acc_1 IS NOT NULL
          THEN acc_1 || ',' END
       || CASE WHEN acc_2 IS NOT NULL
               AND  (acc_1 IS NULL OR acc_1 <> acc_2)
               THEN acc_2 || ',' END
       || CASE WHEN acc_3 IS NOT NULL
               AND  (acc_1 IS NULL OR acc_1 <> acc_3)
               AND  (acc_2 IS NULL OR acc_2 <> acc_3)
               THEN acc_3 || ',' END
       || CASE WHEN acc_4 IS NOT NULL
               AND  (acc_1 IS NULL OR acc_1 <> acc_4)
               AND  (acc_2 IS NULL OR acc_2 <> acc_4)
               AND  (acc_3 IS NULL OR acc_3 <> acc_4)
               THEN acc_4 || ',' END AS accounts
FROM   myTable;

这将输出:

USER ACCOUNTS
1 t1,
2 t2,
3 t3,

注意:如果要删除尾随的逗号,可以使用RTRIM(或者如果帐号可能包含逗号,则可以使用SUBSTR到倒数第二个字符)

或者,可以将行解开并重新聚合行(这需要键入更少,但与在初始行上使用CASE表达式进行所有操作相比,将行解开然后重新聚合效率较低):

SELECT "USER",
       LISTAGG(DISTINCT acc) WITHIN GROUP (ORDER BY type) AS accounts
FROM   myTable
UNPIVOT (acc FOR type IN (acc_1, acc_2, acc_3, acc_4))
GROUP BY "USER"

这将输出:

USER ACCOUNTS
1 t1
2 t2
3 t3

fiddle

英文:

Given the sample data:

create table myTable ("USER", acc_1, acc_2,acc_3,acc_4) as
select 1, 't1', 't1', null, null from dual union all
select 2, 't2', null, 't2', 't2' from dual union all
select 3, null, 't3', null, null from dual;

You can use CASE expressions (which is more to type but will only require a single table scan and uses simple, fast comparisons):

SELECT "USER",
          CASE WHEN acc_1 IS NOT NULL
          THEN acc_1 || ',' END
       || CASE WHEN acc_2 IS NOT NULL
               AND  (acc_1 IS NULL OR acc_1 <> acc_2)
               THEN acc_2 || ',' END
       || CASE WHEN acc_3 IS NOT NULL
               AND  (acc_1 IS NULL OR acc_1 <> acc_3)
               AND  (acc_2 IS NULL OR acc_2 <> acc_3)
               THEN acc_3 || ',' END
       || CASE WHEN acc_4 IS NOT NULL
               AND  (acc_1 IS NULL OR acc_1 <> acc_4)
               AND  (acc_2 IS NULL OR acc_2 <> acc_4)
               AND  (acc_3 IS NULL OR acc_3 <> acc_4)
               THEN acc_4 || ',' END AS accounts
FROM   myTable;

Which outputs:

USER ACCOUNTS
1 t1,
2 t2,
3 t3,

Note: if you want to remove the trailing comma then you can use RTRIM (or SUBSTR up to the penultimate character if the account numbers may contain commas).

or, unpivot and the re-aggregate the rows (which is much less to type but it is going to be less efficient to unpivot and then re-aggregate compared to doing it all on the initial rows with CASE expressions):

SELECT "USER",
       LISTAGG(DISTINCT acc) WITHIN GROUP (ORDER BY type) AS accounts
FROM   myTable
UNPIVOT (acc FOR type IN (acc_1, acc_2, acc_3, acc_4))
GROUP BY "USER"

Which outputs:

USER ACCOUNTS
1 t1
2 t2
3 t3

fiddle

答案3

得分: 0

使用COALESCE来选择每个用户的第一个非空的acc值:

select user, coalesce(acc_1, acc_2, acc_3, acc_4) as acc
from myTable
英文:

Simply use COALESCE to pick the first non-null acc value for each user:

select user, coalesce(acc_1, acc_2, acc_3, acc_4) as acc
from myTable

huangapple
  • 本文由 发表于 2023年4月19日 15:57:57
  • 转载请务必保留本文链接:https://go.coder-hub.com/76052020.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定