views:

244

answers:

4

I have a string of email recipients in the format like this:

 DECLARE @recipients VARCHAR(MAX);
 ....
 PRINT @recipients;
 /* the result
 [email protected];[email protected];[email protected];...
 */

"SELECT DISTIECT ..." is a simple and powerful SQL statement, but it works against a table. Is there a simple way to select distinct recipient from the recipient list variable like FOR loop in C# or Ruby?

 FOR @recipient IN @recipients
 BEGIN
    -- send email to @recipient
 END

By the way, I am using TSQL in SQL server 2005.

A: 

What you want in a Split function that will return a table for you to work with.

There are uncountable implementations around but I'm not aware of a built-in one, or a consensus of the 'best'.

Tom Ritter
Your suggestion looks like this is not a simple TSQL way. The function takes two parameters, one of recipients and another as delimiter like ';' as default. Is that right?
David.Chu.ca
Sure. You can make the delimiter whatever you like as default. As far as "simple T-SQL way" - functions are a built-in part of T-SQL, Table Valued functions have been around since SQL Server 2005 I believe.
Tom Ritter
@David Chu: there is no 'simple' way in Sql Server.
Joel Coehoorn
Until SQL supports arrays, you will have to achieve this the manual way - by parsing a delimited string.
Ian Kemp
+2  A: 

Here's a solution for you that uses a temporary table.

declare @emails varchar(2000)
set @emails = '[email protected];[email protected];[email protected];'

declare @results table (row int identity(1,1), email varchar(500))

while ((select charindex(';',@emails)) > 0)
begin   
    insert into @results select substring(@emails,1,charindex(';',@emails))
    select @emails = substring(@emails,charindex(';',@emails)+1,len(@emails))
end

select distinct email from @results

The idea is to continously parse the email from the string, insert it into a temporary table, and remove the parsed email from the remaining string.

You can use loop through the temporary table afterward to send your individual emails.

Some Canuck
+1  A: 

e.g.

CREATE FUNCTION dbo.Split (@sep char(1), @s varchar(512))
RETURNS table
AS
RETURN (
    WITH Pieces(pn, start, stop) AS (
      SELECT 1, 1, CHARINDEX(@sep, @s)
      UNION ALL
      SELECT pn + 1, stop + 1, CHARINDEX(@sep, @s, stop + 1)
      FROM Pieces
      WHERE stop > 0
    )
    SELECT pn,
      SUBSTRING(@s, start, CASE WHEN stop > 0 THEN stop-start ELSE 512 END) AS s
    FROM Pieces
  )
GO
adolf garlic
I got error:Types don't match between the anchor and the recursive part in column "start" of recursive query "Pieces"
David.Chu.ca
OK. I got the error resolved. I used @s varchar(max). Not sure why max is not working here. 512 or 4000 is OK
David.Chu.ca
A: 

I use a function like the one below to deal with a similar situation when receiving lists like that from the front end. Then you can just use this code to return the string as a table instead:

SELECT DISTINCT String FROM dbo.GetTableFromStringList(@recipients)

You probably want to do the actual sending of the email in something other than T-SQL code though.

Here's the function:

CREATE FUNCTION [dbo].[GetTableFromStringList]
(
    @StringList VARCHAR(1000),
    @Delimiter CHAR(1) = ','
)
RETURNS @Results TABLE
(
    String VARCHAR(1000) NOT NULL
)
AS
BEGIN
    DECLARE
     @string  VARCHAR(1000),
     @position SMALLINT

    SET @StringList = LTRIM(RTRIM(@StringList)) + @Delimiter
    SET @position = CHARINDEX(@Delimiter, @StringList)

    WHILE (@position > 0)
    BEGIN
     SET @string = LTRIM(RTRIM(LEFT(@StringList, @position - 1)))

     IF (@string <> '')
     BEGIN
      INSERT INTO @Results (String) VALUES (@string)
     END

     SET @StringList = RIGHT(@StringList, LEN(@StringList) - @position)
     SET @position = CHARINDEX(@Delimiter, @StringList, 1)
    END

    RETURN
END
Tom H.