英文:
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 |
英文:
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 |
答案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
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论