更新或删除拆分数据

时间:2015-08-04 14:37:20

标签: sql sql-server sql-server-2008-r2

在客户表中,我有电子邮件列,其中可能包含多个以(;)分隔的电子邮件。
我使用拆分功能为每个客户分隔电子邮件:

Cust1 --->email1
cust1 --->email2
cust1 ---> emailN

我可以向同一位客户添加更多电子邮件。
我希望能够更新或删除拆分的电子邮件,换句话说,如果email2 = abc@company.com我想将其更改为xyz@company.com或删除它。
是否可以使用分离功能?或任何其他方式?

这是我的分割功能

CREATE FUNCTION [dbo].[fnSplitString] 
( 
    @string NVARCHAR(MAX), 
    @delimiter CHAR(1) 
) 
RETURNS @output TABLE(splitdata NVARCHAR(MAX) 
) 
BEGIN 
    DECLARE @start INT, @end INT 
    SELECT @start = 1, @end = CHARINDEX(@delimiter, @string) 
    WHILE @start < LEN(@string) + 1 BEGIN 
        IF @end = 0  
            SET @end = LEN(@string) + 1

        INSERT INTO @output (splitdata)  
        VALUES(SUBSTRING(@string, @start, @end - @start)) 
        SET @start = @end + 1 
        SET @end = CHARINDEX(@delimiter, @string, @start)

    END 
    RETURN 
END

调用该功能拆分电子邮件:

select tb1.custId, split.splitdata from customers tb1
outer apply [dbo].[fnSplitString] (tb1.email,';') split
where tb1.Email like '%;%'

向同一客户添加新电子邮件:

UPDATE Customers set Email=Email+';new Email' Where CustId='customerId'

更新或删除现有电子邮件,有什么建议吗?

提前致谢

1 个答案:

答案 0 :(得分:2)

首先,您的分割功能不是最佳的。它正在以RBAR方式进行分割。有许多方法可以以基于集合的方式执行此操作。这是一个使用XML,取自Aaron Bertrand的article

我更喜欢Jeff Moden的DelimitedSplit8K,但为了简单起见,我将使用XML拆分。

CREATE FUNCTION dbo.SplitStrings_XML
(
   @List       NVARCHAR(MAX),
   @Delimiter  NVARCHAR(255)
)
RETURNS TABLE
WITH SCHEMABINDING
AS
   RETURN 
   (  
      SELECT Item = y.i.value('(./text())[1]', 'nvarchar(4000)')
      FROM 
      ( 
        SELECT x = CONVERT(XML, '<i>' 
          + REPLACE(@List, @Delimiter, '</i><i>') 
          + '</i>').query('.')
      ) AS a CROSS APPLY x.nodes('i') AS y(i)
   );

现在您已经拥有了基于集合的拆分器,现在是时候进行CRUD操作了:

SELECT分割的电子邮件:

SELECT
    c.CustomerId,
    Email = s.Item
FROM Customer c
CROSS APPLY dbo.SplitStrings_XML(c.Emails, ';') s

ADDEmail到特定Customer

DECLARE @email NVARCHAR(100) = 'abc@company.com'
UPDATE Customer
    SET Emails = Emails + ';' + @email 
WHERE
    CustomerId = 1
    AND CHARINDEX(@email, Emails) = 0 -- Prevent duplicate Email

UPDATE Email Customer DECLARE @to_update NVARCHAR(100) = 'abc@company.com', @new_email NVARCHAR(100) = 'xyz@company.com'; ;WITH Cte AS( SELECT c.CustomerId, Email = CASE WHEN s.Item = @to_update THEN @new_email ELSE s.Item END FROM Customer c CROSS APPLY dbo.SplitStrings_XML(c.Emails, ';') s ) UPDATE c SET Emails = STUFF(( SELECT ';' + Email FROM Cte WHERE CustomerId = c.CustomerId FOR XML PATH(''), type).value('.[1]','nvarchar(max)') ,1, 1, '') FROM Customer c SELECT * FROM Customer REPLACE

UPDATE Customer
    SET Emails = REPLACE(Emails, @to_update, @new_email)
WHERE CustomerId = 1

您也可以使用DELETE

Email

从列表中DECLARE @to_delete NVARCHAR(100) = 'abc@company.com'; ;WITH Cte AS( SELECT c.CustomerId, Email = s.Item FROM Customer c CROSS APPLY dbo.SplitStrings_XML(c.Emails, ';') s WHERE s.Item <> @to_delete ) UPDATE c SET Emails = STUFF(( SELECT ';' + Email FROM Cte WHERE CustomerId = c.CustomerId FOR XML PATH(''), type).value('.[1]','nvarchar(max)') ,1, 1, '') FROM Customer c SELECT * FROM Customer REPLACE

DECLARE @to_delete NVARCHAR(100) = 'abc@company.com';
UPDATE Customer
    SET Emails = REPLACE(Emails, @to_delete + ';', '')
WHERE CustomerId = 1

您也可以使用$userAmt

$points

现在,我将把它留作练习,将它们转换为存储过程。 :)