从 Oracle 中的逗号分隔变量中删除重复值
Remove duplicate values from comma separated variable in Oracle
我有一个变量 (称为:all_email_list),它总共包含 3 个电子邮件地址列表。 (我发现了一些类似的问题,但没有正确的解决方案)
示例:test@asd.com, test2@asd.com,test@asd.com,test3@asd.com, test4@asd.com,test2@asd.com
(它可以在逗号之间包含空格,但并非始终如此)
期望的输出:test@asd.com, test2@asd.com,test3@asd.com,test4@asd.com
declare
first_email_list varchar2(4000);
second_email_list varchar2(4000);
third_email_list varchar2(4000);
all_email_list varchar2(4000);
begin
select listagg(EMAIL,',') into first_email_list from UM_USER a left join UM_USERROLLE b on (a.mynetuser=b.NT_NAME) left join UM_RULES c on (c.id=b.RULEID) where RULEID = 902;
select listagg(EMAIL,',') into second_email_list from table2 where CFT_ID =:P25_CFT_TEAM;
select EMAIL into third_email_list from table3 WHERE :P25_ID = ID;
all_email_list:= first_email_list || ',' || second_email_list || ',' || third_email_list;
dbms_output.put_line(all_email_list);
end;
有什么简单的方法可以解决这个问题吗?也许通过正则表达式。
解决方案说明。使用 CTE 首先将电子邮件列表拆分为每行 1 个电子邮件地址的行 (testd_rows)。然后 select 来自 testd_rows 的不同行(testd_rows_unique),最后将它们与 listagg 放回一起。从 19c 开始,您可以将 LISTAGG
与 DISTINCT
关键字一起使用。
set serveroutput on size 999999
clear screen
declare
all_email_list varchar2(4000);
l_unique_email_list varchar2(4000);
begin
all_email_list := 'test@asd.com, test2@asd.com,test@asd.com,test3@asd.com, test4@asd.com,test2@asd.com';
WITH testd_rows(email) AS
(
select regexp_substr (all_email_list, '[^, ]+', 1, rownum) split
from dual
connect by level <= length (regexp_replace (all_email_list, '[^, ]+')) + 1
), testd_rows_unique(email) AS
(
SELECT distinct email FROM testd_rows
)
SELECT listagg(email, ',') WITHIN GROUP (ORDER BY email)
INTO l_unique_email_list
FROM testd_rows_unique;
dbms_output.put_line(l_unique_email_list);
end;
/
test2@asd.com,test3@asd.com,test4@asd.com,test@asd.com
但是...为什么要将行转换为逗号分隔的字符串,然后删除重复数据?使用 UNION
删除单个 SELECT
语句中的重复值,并对值执行 LISTAGG
。那时不需要正则表达式。 UNION
将跳过重复项,而不是 UNION ALL
returns 所有行。
DECLARE
all_email_list varchar2(4000);
BEGIN
WITH all_email (email) AS
(
select email from UM_USER a left join UM_USERROLLE b on (a.mynetuser=b.NT_NAME) left join UM_RULES c on (c.id=b.RULEID) where RULEID = 902
UNION
select email from table2 where CFT_ID =:P25_CFT_TEAM
UNION
select email from table3 WHERE :P25_ID = ID
)
SELECT listagg(email, ',') WITHIN GROUP (ORDER BY email)
INTO all_email_list
FROM all_email;
dbms_output.put_line(all_email_list);
END;
/
您可以利用 apex_string.split table 函数来简化代码。
12c+ 让它真正干净
select listagg(distinct column_value,',') within group (order by null)
from apex_String.split(replace('test@asd.com, test2@asd.com,test@asd.com,test3@asd.com, test4@asd.com,test2@asd.com'
,' ')
,',')
11g 需要包装 table() 并且 listagg 不支持不同。
select listagg(email,',') within group (order by null)
from
(select distinct column_value email
from table(apex_String.split(replace('test@asd.com, test2@asd.com,test@asd.com,test3@asd.com, test4@asd.com,test2@asd.com',' '),','))
);
我有一个变量 (称为:all_email_list),它总共包含 3 个电子邮件地址列表。 (我发现了一些类似的问题,但没有正确的解决方案)
示例:test@asd.com, test2@asd.com,test@asd.com,test3@asd.com, test4@asd.com,test2@asd.com
(它可以在逗号之间包含空格,但并非始终如此)
期望的输出:test@asd.com, test2@asd.com,test3@asd.com,test4@asd.com
declare
first_email_list varchar2(4000);
second_email_list varchar2(4000);
third_email_list varchar2(4000);
all_email_list varchar2(4000);
begin
select listagg(EMAIL,',') into first_email_list from UM_USER a left join UM_USERROLLE b on (a.mynetuser=b.NT_NAME) left join UM_RULES c on (c.id=b.RULEID) where RULEID = 902;
select listagg(EMAIL,',') into second_email_list from table2 where CFT_ID =:P25_CFT_TEAM;
select EMAIL into third_email_list from table3 WHERE :P25_ID = ID;
all_email_list:= first_email_list || ',' || second_email_list || ',' || third_email_list;
dbms_output.put_line(all_email_list);
end;
有什么简单的方法可以解决这个问题吗?也许通过正则表达式。
解决方案说明。使用 CTE 首先将电子邮件列表拆分为每行 1 个电子邮件地址的行 (testd_rows)。然后 select 来自 testd_rows 的不同行(testd_rows_unique),最后将它们与 listagg 放回一起。从 19c 开始,您可以将 LISTAGG
与 DISTINCT
关键字一起使用。
set serveroutput on size 999999
clear screen
declare
all_email_list varchar2(4000);
l_unique_email_list varchar2(4000);
begin
all_email_list := 'test@asd.com, test2@asd.com,test@asd.com,test3@asd.com, test4@asd.com,test2@asd.com';
WITH testd_rows(email) AS
(
select regexp_substr (all_email_list, '[^, ]+', 1, rownum) split
from dual
connect by level <= length (regexp_replace (all_email_list, '[^, ]+')) + 1
), testd_rows_unique(email) AS
(
SELECT distinct email FROM testd_rows
)
SELECT listagg(email, ',') WITHIN GROUP (ORDER BY email)
INTO l_unique_email_list
FROM testd_rows_unique;
dbms_output.put_line(l_unique_email_list);
end;
/
test2@asd.com,test3@asd.com,test4@asd.com,test@asd.com
但是...为什么要将行转换为逗号分隔的字符串,然后删除重复数据?使用 UNION
删除单个 SELECT
语句中的重复值,并对值执行 LISTAGG
。那时不需要正则表达式。 UNION
将跳过重复项,而不是 UNION ALL
returns 所有行。
DECLARE
all_email_list varchar2(4000);
BEGIN
WITH all_email (email) AS
(
select email from UM_USER a left join UM_USERROLLE b on (a.mynetuser=b.NT_NAME) left join UM_RULES c on (c.id=b.RULEID) where RULEID = 902
UNION
select email from table2 where CFT_ID =:P25_CFT_TEAM
UNION
select email from table3 WHERE :P25_ID = ID
)
SELECT listagg(email, ',') WITHIN GROUP (ORDER BY email)
INTO all_email_list
FROM all_email;
dbms_output.put_line(all_email_list);
END;
/
您可以利用 apex_string.split table 函数来简化代码。
12c+ 让它真正干净
select listagg(distinct column_value,',') within group (order by null)
from apex_String.split(replace('test@asd.com, test2@asd.com,test@asd.com,test3@asd.com, test4@asd.com,test2@asd.com'
,' ')
,',')
11g 需要包装 table() 并且 listagg 不支持不同。
select listagg(email,',') within group (order by null)
from
(select distinct column_value email
from table(apex_String.split(replace('test@asd.com, test2@asd.com,test@asd.com,test3@asd.com, test4@asd.com,test2@asd.com',' '),','))
);