Разбить строку в строке базы данных и скопировать результаты в разные строки - SQL Server - PullRequest
1 голос
/ 23 июня 2010

Я создал приложение для отправки почты пользователям. Я использую базу данных, в которой некоторым пользователям назначено более одного адреса электронной почты.

Name                        Mail
-----------------------------------------
BusinessXPTO     mail1@xpto.com;mail2@xpto.com

Столбец электронной почты может содержать несколько писем, разделенных точкой с запятой. Я хочу разбить строку, чтобы каждое письмо помещалось в отдельную строку.

Name                        Mail
-----------------------------------------
BusinessXPTO         mail1@xpto.com
BusinessXPTO         mail2@xpto.com

Какое лучшее решение?

Спасибо

Ответы [ 3 ]

3 голосов
/ 23 июня 2010

Вот простой пример использования функций XML в SQL Server 2005 и выше. Я взял это дословно от здесь , но есть много примеров, если вы Google "split string sql server xml"

DECLARE @xml as xml,@str as varchar(100),@delimiter as varchar(10)
SET @str='A,B,C,D,E'
SET @delimiter =','
SET @xml = cast(('<X>'+replace(@str,@delimiter ,'</X><X>')+'</X>') as xml)
SELECT N.value('.', 'varchar(10)') as value FROM @xml.nodes('X') as T(N)

Существуют и другие решения с курсорами, но этот подход хорошо сработал для меня.

1 голос
/ 23 июня 2010

Ниже приведен UDF, который я использую для разделения значений на произвольный разделитель.С тех пор я изменил свою функцию так, чтобы она была встроенной табличной функцией (вместо табличной функции с несколькими операторами) и больше не опиралась на таблицу Numbers, поскольку она строится на лету.

CREATE FUNCTION dbo.udf_Split
(   
    @DelimitedList nvarchar(max)
    , @Delimiter nvarchar(2) = ','
)
RETURNS TABLE 
AS
RETURN 
    (
    With CorrectedList As
        (
        Select Case When Left(@DelimitedList, Len(@Delimiter)) <> @Delimiter Then @Delimiter Else '' End
            + @DelimitedList
            + Case When Right(@DelimitedList, Len(@Delimiter)) <> @Delimiter Then @Delimiter Else '' End
            As List
            , Len(@Delimiter) As DelimiterLen
        )
        , Numbers As 
        (
        Select Row_Number() Over ( Order By c1.object_id ) As Value
        From sys.columns As c1
            Cross Join sys.columns As c2
        )
    Select CharIndex(@Delimiter, CL.list, N.Value) + CL.DelimiterLen As Position
        , Substring (
                    CL.List
                    , CharIndex(@Delimiter, CL.list, N.Value) + CL.DelimiterLen     
                    , CharIndex(@Delimiter, CL.list, N.Value + 1)                           
                        - ( CharIndex(@Delimiter, CL.list, N.Value) + CL.DelimiterLen ) 
                    ) As Value
    From CorrectedList As CL
        Cross Join Numbers As N
    Where N.Value < Len(CL.List)
        And Substring(CL.List, N.Value, CL.DelimiterLen) = @Delimiter
    )

Вот пример вызова:

Select T.Name, Address.Value
From MyTable As T
    Cross Apply dbo.udf_Split( T.Mail, ';' ) As Addresses
0 голосов
/ 29 мая 2012

В Oracle

Вот пример для предоставленного примера:

select 'BusinessXPTO' name, 'mail1@xpto.com;mail2@xpto.com' mail from dual;

Вот как разбить столбец mail на отдельные строки

select 'BusinessXPTO' name, regexp_substr('mail_1@xpto.com;mail_2@xpto.com','[^;]+',1, rn) mail  
from dual 
cross join 
    (select rownum rn from 
        (select max(length(regexp_replace('mail_1@xpto.com;mail_2@xpto.com', '[^;]+'))) + 1 mx from dual) 
    connect by level <= mx ) 
where regexp_substr ('mail1@xpto.com;mail2@xpto.com', '[^;]+', 1, rn) is not null 
order by rn;

Вот результат

NAME            MAIL
BusinessXPTO    mail_1@xpto.com
BusinessXPTO    mail_2@xpto.com
...