Domanda

I am trying to split a single string containing multiple email address data into three variables. The strings mark the start/end of an email address with the ; character.

An example string would be:

'joebloggs@gmailcom;jimbowen@aol.com;dannybaker@msn.com'

The code I currently have for this is as follows:

    DECLARE @Email VARCHAR(100),
        @Email2 VARCHAR(100),
        @Email3 VARCHAR(100)

SET @Email = 'joebloggs@gmailcom;jimbowen@aol.com;dannybaker@msn.com'

SET @Email2 = SUBSTRING(@Email, CHARINDEX(';', @Email)+1, LEN(@Email))
SET @Email3 = SUBSTRING(@Email, CHARINDEX(';', @Email)+1, LEN(@Email))
SET @Email = SUBSTRING(@Email, 1, CHARINDEX(';', @Email)-1)

Unfortunately this doesn't seem to work. Could someone please point out where I am going wrong and what I should do to fix my problem?

Thanks in advance.

È stato utile?

Soluzione

Assuming that there will always be 3 email addresses - the following seems to work;

DECLARE @Email VARCHAR(100),
        @Email2 VARCHAR(100),
        @Email3 VARCHAR(100)

SET @Email = 'joebloggs@gmailcom;jimbowen@aol.com;dannybaker@msn.com'

SELECT   @Email     = LEFT(@Email, CHARINDEX(';', @Email) - 1)
        ,@Email2    = SUBSTRING (   
                                    @Email, 
                                    CHARINDEX(';', @Email) + 1, 
                                    CHARINDEX(';', @Email, CHARINDEX(';', @Email) + 1) - LEN(LEFT(@Email, CHARINDEX(';', @Email) )) - 1
                                )
        ,@Email3    = RIGHT(@Email, CHARINDEX(';', @Email)-1)

Altri suggerimenti

This solution:

create function dbo.SplitString 
(
    @str nvarchar(max), 
    @separator char(1)
)
returns table
AS
return (
with tokens(p, a, b) AS (
    select 
        cast(1 as bigint), 
        cast(1 as bigint), 
        charindex(@separator, @str)
    union all
    select
        p + 1, 
        b + 1, 
        charindex(@separator, @str, b + 1)
    from tokens
    where b > 0
)
select
    p-1 ItemIndex,
    substring(
        @str, 
        a, 
        case when b > 0 then b-a ELSE LEN(@str) end) 
    AS Item
from tokens
);

GO

Taken from How do I split a string so I can access item x

In SQL Server 2016 you can use the built-in STRING_SPLIT function.

SELECT value FROM STRING_SPLIT(@var, ';')

Try using XML nodes to split and parse your string. Code sample below:

declare @Email as varchar(100), @del as varchar(10), @xml as xml;
set @Email='joebloggs@gmailcom;jimbowen@aol.com;dannybaker@msn.com';
set @del =';';
set @xml = '<root><c>' + replace(@Email,@del,'</c><c>') + '</c></root>';
select email.value('.','varchar(100)') as Email
from @xml.nodes('//root/c') as records(email);

Here this works I came across it quite sometime ago. Cannot take any credit for the work but this will work perfectly.

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 *from dbo.fnSplitString('joebloggs@gmailcom;jimbowen@aol.com;dannybaker@msn.com',';')

I wrote this function that I use on a regular basis...

CREATE FUNCTION func_split(@value VARCHAR(8000), @delim CHAR)
RETURNS
    @outtable TABLE (
        i INTEGER,
        value VARCHAR(1024)
    )
AS
BEGIN
    DECLARE @pos INTEGER
    DECLARE @count INTEGER

    IF LEN(@value) > 0
    BEGIN
        SET @count = 1
        SET @value = @value + @delim
        SET @pos = CHARINDEX(@delim, @value, 1)
        WHILE @pos > 0
        BEGIN
            INSERT INTO @outtable (i, value) VALUES (@count, LEFT(@value, @pos - 1))
            SET @value = RIGHT(@value, LEN(@value) - @pos)
            SET @pos = CHARINDEX(@delim, @value, 1)
            SET @count = @count + 1
        END
    END

    RETURN
END

You when then call it with...

DECLARE @emails AS TABLE (
    i INTEGER,
    value VARCHAR(1024)
)

INSERT INTO @split SEELCT * FROM func_split('joebloggs@gmailcom;jimbowen@aol.com;dannybaker@msn.com', ';');

...and you end up with a temp table full of email addresses, i being their input order.

Your best bet is to turn the delimited string into columnar form and work from there.

You can use the iterative method, or the method using the Numbers table (which I prefer):

declare 
    @list varchar(1000),
    @sep char(1)

set @list = 'joebloggs@gmailcom;jimbowen@aol.com;dannybaker@msn.com';
set @sep = ';'

-- iterative method
declare @res table (
    c varchar(100)
)

declare 
    @pos_start int,
    @pos_end int,
    @len_sep int,
    @exit int

select @pos_start = 1, @pos_end = 1, @len_sep = len(@sep),  @exit = 0

while @exit = 0
begin
    set @pos_end = charindex(@sep, @list, @pos_start)

    if @pos_end <= 0 begin
        set @pos_end = len(@list) + 1
        set @exit = 1
    end

    insert @res(c) select substring(@list, @pos_start, @pos_end - @pos_start)

    set @pos_start = @pos_end + @len_sep
end

select * from @res

-- the Numbers table method
select substring(@list, n, charindex(@sep, @list + @sep, n) - n)
from numbers 
where substring(@sep + @list, n, 1) = @sep
and n < len(@list) + 1
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top