Sql server 如何使用transact-sql组合多列中的值并删除任何重复项

Sql server 如何使用transact-sql组合多列中的值并删除任何重复项,sql-server,tsql,Sql Server,Tsql,我在sql server数据库中有一个表,其中包含四列电子邮件地址,即Email1、Email2、Email3和Email4。我需要创建一个功能,返回一个组合的电子邮件地址,并删除任何重复的电子邮件 e、 g.Email1和Email3可能有相同的地址email@email.com我只需要在组合字符串中包含一次 我已经编写了一个函数,如下所示,它确实返回组合值,但不确定如何删除重复的电子邮件 Create FUNCTION [dbo].[CombineAndCommaSeparateEmails

我在sql server数据库中有一个表,其中包含四列电子邮件地址,即Email1、Email2、Email3和Email4。我需要创建一个功能,返回一个组合的电子邮件地址,并删除任何重复的电子邮件

e、 g.Email1和Email3可能有相同的地址email@email.com我只需要在组合字符串中包含一次

我已经编写了一个函数,如下所示,它确实返回组合值,但不确定如何删除重复的电子邮件

Create FUNCTION [dbo].[CombineAndCommaSeparateEmails] 

(@Email1 VARCHAR(250),@Email2 VARCHAR(250),@Email3 VARCHAR(250),@Email4 VARCHAR(250))

RETURNS VARCHAR(250)

AS BEGIN

DECLARE @combinedEmails VARCHAR(1000)

Set @combinedEmails=   
concat(
Rtrim(Ltrim(Case when @EMAIL1 is not null then @EMAIL1+',' end)),
Rtrim(Ltrim(Case when @EMAIL2 is not null then @EMAIL2+',' end)),
Rtrim(Ltrim(Case when @EMAIL3 is not null then @EMAIL3+',' end)),
Rtrim(Ltrim(@EMAIL4)))


Set @combinedEmails=   case 
when RIGHT(@combinedEmails,1)=',' then substring(@combinedEmails,1,len(@combinedEmails)-1)
else @combinedEmails END    

RETURN @combinedEmails
END
有什么想法吗?谢谢

您可以使用OUTER APPLY获取不同的电子邮件,然后使用任何方法连接它们:

WITH cte AS (
  SELECT id, <other_columns>, sub.email
  FROM your_table t
  OUTER APPLY (SELECT DISTINCT email
               FROM (VALUES (t.Email1)
                           ,(t.Email2)
                           ,(t.Email3)
                           ,(t.Email4)
                     ) s(email)
             ) sub
)
SELECT id, <other_columns>, STRING_AGG(cte.email, ';') AS concatenated_email
FROM cte
GROUP BY id,<other_columns>;
在这里,我使用了SQL Server vNext提供的电子邮件。

您可以使用外部应用程序获取不同的电子邮件,然后使用任何方法将它们连接起来:

WITH cte AS (
  SELECT id, <other_columns>, sub.email
  FROM your_table t
  OUTER APPLY (SELECT DISTINCT email
               FROM (VALUES (t.Email1)
                           ,(t.Email2)
                           ,(t.Email3)
                           ,(t.Email4)
                     ) s(email)
             ) sub
)
SELECT id, <other_columns>, STRING_AGG(cte.email, ';') AS concatenated_email
FROM cte
GROUP BY id,<other_columns>;

在这里,我使用了SQL Server vNext中提供的选项。

如果您想保留UDF,可以使用另一个选项

Declare @EMail1 varchar(50) = 'some@email.com'
Declare @EMail2 varchar(50) = 'some@email.com'
Declare @EMail3 varchar(50) = 'someother@email.com'
Declare @EMail4 varchar(50) = 'some@email.com'

Select Stuff((Select Distinct ','+EMails From (values (@EMail1),(@EMail2),(@EMail3),(@EMail4) ) A (EMails) For XML Path('')),1,1,'')
返回

some@email.com,someother@email.com
some@email.com,someother@email.com
作为函数

返回

some@email.com,someother@email.com
some@email.com,someother@email.com

如果要保留自定义项,请选择另一个选项

Declare @EMail1 varchar(50) = 'some@email.com'
Declare @EMail2 varchar(50) = 'some@email.com'
Declare @EMail3 varchar(50) = 'someother@email.com'
Declare @EMail4 varchar(50) = 'some@email.com'

Select Stuff((Select Distinct ','+EMails From (values (@EMail1),(@EMail2),(@EMail3),(@EMail4) ) A (EMails) For XML Path('')),1,1,'')
返回

some@email.com,someother@email.com
some@email.com,someother@email.com
作为函数

返回

some@email.com,someother@email.com
some@email.com,someother@email.com

使用一些虚拟试验数据:

CREATE TABLE people (
    ID INT,
    Name VARCHAR(50),
    Email1 VARCHAR(50),
    Email2 VARCHAR(50),
    Email3 VARCHAR(50),
    Email4 VARCHAR(50)
)

INSERT INTO people (ID, Name, Email1, Email2, Email3, Email4) VALUES
(1, 'John Smith', 'jsmith@gmail.com', 'johns@work.com', '', 'jsmith@gmail.com'),
(2, 'Jane Doe', 'janedoe2001@gmail.com', 'janed@business.com', '', ''),
(3, 'Roger White', 'rwhite@gmail.com', 'whitey@somewhere.com', 'rwhite@gmail.com', 'rwhite@gmail.com');
我将创建一个CTE来返回所有唯一的电子邮件地址,然后使用FOR XML PATH来组合它们:

WITH uniqueEmails (ID, Name, Email) AS
(
    SELECT ID, Name, Email1 AS Email
    FROM people
    UNION
    SELECT ID, Name, Email2 AS Email
    FROM people
    UNION
    SELECT ID, Name, Email3 AS Email
    FROM people
    UNION
    SELECT ID, Name, Email4 AS Email
    FROM people
)
SELECT DISTINCT
    e.ID,
    e.Name, 
    STUFF(
            (
                SELECT ',' + e2.Email
                FROM uniqueEmails e2
                WHERE e2.ID = e.ID
                AND ISNULL(e2.Email,'') <> ''
                GROUP BY e2.Email
                ORDER BY e2.Email
                FOR XML PATH('')
            ), 1, 1, ''
         ) AS Emails
FROM uniqueEmails e
WHERE ISNULL(e.Email,'') <> ''

使用一些虚拟试验数据:

CREATE TABLE people (
    ID INT,
    Name VARCHAR(50),
    Email1 VARCHAR(50),
    Email2 VARCHAR(50),
    Email3 VARCHAR(50),
    Email4 VARCHAR(50)
)

INSERT INTO people (ID, Name, Email1, Email2, Email3, Email4) VALUES
(1, 'John Smith', 'jsmith@gmail.com', 'johns@work.com', '', 'jsmith@gmail.com'),
(2, 'Jane Doe', 'janedoe2001@gmail.com', 'janed@business.com', '', ''),
(3, 'Roger White', 'rwhite@gmail.com', 'whitey@somewhere.com', 'rwhite@gmail.com', 'rwhite@gmail.com');
我将创建一个CTE来返回所有唯一的电子邮件地址,然后使用FOR XML PATH来组合它们:

WITH uniqueEmails (ID, Name, Email) AS
(
    SELECT ID, Name, Email1 AS Email
    FROM people
    UNION
    SELECT ID, Name, Email2 AS Email
    FROM people
    UNION
    SELECT ID, Name, Email3 AS Email
    FROM people
    UNION
    SELECT ID, Name, Email4 AS Email
    FROM people
)
SELECT DISTINCT
    e.ID,
    e.Name, 
    STUFF(
            (
                SELECT ',' + e2.Email
                FROM uniqueEmails e2
                WHERE e2.ID = e.ID
                AND ISNULL(e2.Email,'') <> ''
                GROUP BY e2.Email
                ORDER BY e2.Email
                FOR XML PATH('')
            ), 1, 1, ''
         ) AS Emails
FROM uniqueEmails e
WHERE ISNULL(e.Email,'') <> ''

这首先使用交叉应用和值来取消PIVOTS以删除重复项,然后使用XML路径内容将其重新组合在一起

DROP TABLE #TMP
CREATE TABLE #TMP (ID INT
                    ,Text1 VARCHAR(255)
                    ,Text2 VARCHAR(255)
                    ,Text3 VARCHAR(255)
                    ,Text4 VARCHAR(255)
                    )

INSERT INTO  #TMP VALUES
(1,'aaa','bbb','ccc','ddd')
,(2,'fff','ggg','fff','hhh')    --Row With Duplicate

;WITH cte_UP    --Remove Duplicates Using an unpivot CROSS APPLY with VALUES
    AS
    (
    SELECT DISTINCT
        T.ID
        ,U.Textn
    FROM
        #TMP T CROSS APPLY (VALUES (T.Text1)
                                    ,(T.Text2)
                                    ,(T.Text3)
                                    ,(T.Text4))
                                    U(Textn)
    )
--USE XML STUFF TO CONCATENATE UNIQUE VALUES
SELECT 
    ID,
    STUFF((
        SELECT ','+ cast(Textn AS NVARCHAR(255))
        FROM cte_UP b
        WHERE a.ID = b.ID
        FOR XML PATH('')
        )
,1,1,'') AS TextN
FROM cte_UP a
GROUP BY a.ID

这首先使用交叉应用和值来取消PIVOTS以删除重复项,然后使用XML路径内容将其重新组合在一起

DROP TABLE #TMP
CREATE TABLE #TMP (ID INT
                    ,Text1 VARCHAR(255)
                    ,Text2 VARCHAR(255)
                    ,Text3 VARCHAR(255)
                    ,Text4 VARCHAR(255)
                    )

INSERT INTO  #TMP VALUES
(1,'aaa','bbb','ccc','ddd')
,(2,'fff','ggg','fff','hhh')    --Row With Duplicate

;WITH cte_UP    --Remove Duplicates Using an unpivot CROSS APPLY with VALUES
    AS
    (
    SELECT DISTINCT
        T.ID
        ,U.Textn
    FROM
        #TMP T CROSS APPLY (VALUES (T.Text1)
                                    ,(T.Text2)
                                    ,(T.Text3)
                                    ,(T.Text4))
                                    U(Textn)
    )
--USE XML STUFF TO CONCATENATE UNIQUE VALUES
SELECT 
    ID,
    STUFF((
        SELECT ','+ cast(Textn AS NVARCHAR(255))
        FROM cte_UP b
        WHERE a.ID = b.ID
        FOR XML PATH('')
        )
,1,1,'') AS TextN
FROM cte_UP a
GROUP BY a.ID

为了澄清,您只需要将每个记录的4个电子邮件字段中的值组合起来,并删除每个记录中的重复项,即如果一个记录在多个列中列出了相同的电子邮件地址?您想要的输出是一个逗号分隔的字符串?这是正确的@3n1gm4只是为了澄清一下,您只需要将每个记录的4个电子邮件字段中的值组合起来,并删除每个记录中的重复项,即如果一个记录在多个列中列出了相同的电子邮件地址?您想要的输出是一个逗号分隔的字符串?没错@3N1GM4