2

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.

coopertkm
  • 727
  • 2
  • 7
  • 10
  • 1
    Are there always only 3 email addresses? – MarkD May 07 '14 at 15:19
  • possible duplicate of [How do I split a string so I can access item x](http://stackoverflow.com/questions/2647/how-do-i-split-a-string-so-i-can-access-item-x) – podiluska May 07 '14 at 15:36

7 Answers7

5

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)
MarkD
  • 5,276
  • 1
  • 14
  • 22
  • +1, They key point being you are using the optional 3rd argument that `CHARINDEX` takes to find the position of a character in a string after a given point to find the second semi-colon (It's always nice to add a little explanation of your answer rather than just giving the code) – GarethD May 07 '14 at 15:32
3

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

Community
  • 1
  • 1
Bacon Bits
  • 30,782
  • 5
  • 59
  • 66
2

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

SELECT value FROM STRING_SPLIT(@var, ';')
Mogsdad
  • 44,709
  • 21
  • 151
  • 275
Jovan MSFT
  • 13,232
  • 4
  • 40
  • 55
1

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);
user353gre3
  • 2,747
  • 4
  • 24
  • 27
0

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',';')
user2600629
  • 559
  • 6
  • 16
0

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.

atheaos
  • 721
  • 2
  • 7
  • 16
0

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
Community
  • 1
  • 1
dean
  • 9,960
  • 2
  • 25
  • 26