从 SQL 到 SPL:在不确定数量的列间去重

某库表有多个字段,每个字段存储一个邮件地址,有可能为空,有可能重复。

Mail_1

Mail_2

Mail_3

Mail_4

Mail_5

a.gmail.com

a.aol.com

a1.gmail.com

a.gmail.com

a1.gmail.com

b.gmail.com

b.aol.com

b1.gmail.com

b.yahoo.com


现在要将多个字段合并为一个字段,去除空值和重复值,用逗号合并起来。

Mail

a.aol.com,a.gmail.com,a1.gmail.com

b.aol.com,b.gmail.com,b.yahoo.com,b1.gmail.com

支持 array 等数组函数的数据库 / 计算平台,比如 azure-databricks,SQL 这样写:

SELECT concat_ws(',', array_distinct(array(Mail_1, Mail_2, Mail_3, Mail_4, Mail_5)), NULL) AS Mail
FROM my_data

SQL Server 等数据库没有 array 函数,一般要用 cross apply 等语句间接实现:

SELECT 
    STRING_AGG(DistinctEmails.Mail, ',') AS Mail
FROM my_data
CROSS APPLY (
    SELECT DISTINCT Mail
    FROM (VALUES (Mail_1), (Mail_2), (Mail_3), (Mail_4), (Mail_5)) AS EmailList(Mail)
    WHERE Mail IS NOT NULL
) AS DistinctEmails
GROUP BY my_data.Mail_1, my_data.Mail_2, my_data.Mail_3, my_data.Mail_4, my_data.Mail_5

SQL必须写出列名,灵活性较差。要想在不确定数量的列间去重,就要用存储过程动态生成列名再执行 SQL,结构将变得复杂。SPL 不必写出列名,且不同的数据源下代码相同:https://try.esproc.com/splx?36f


 A

1

$select * from my_data.txt

2

=A1.new(~.array().id@0().concat@c():Mail)

A1:加载数据。

A2:取当前记录,转为集合,取唯一值并去掉 null,用逗号合并。~ 表示当前记录,函数 id 用于去重,@0 表示去掉 null。

问题来源:https://stackoverflow.com/questions/78188132/how-to-combine-distinct-records-of-multiple-columns-in-sql