2

I'm looking for a way to do this ...

SELECT FirstName, LastName, Split(AddressBlock, '  ', 1), Split(AddressBlock, ' ', 2), PostCode 
FROM Contacts

The arguments I want to pass are ...

  1. The address
  2. The separator (current situation requires 2 spaces but this might be a comma or a space followed by a comma) or something else (it varies).
  3. The address part I want to return (i don't always need all parts of the split result).

I seem to be able to find a few examples of splitting functions about the internet but they return a table containing the entire set of split parts.

My SQL skills aren't that great so I need the answer to be ultra simple. I'm always working with nvarchar data and the function needs to be reusable.

2
  • possibly a duplicate of stackoverflow.com/questions/314824/… Commented May 20, 2010 at 9:18
  • I disagree, on the basis that I only want to extract certain parts of the plist result and do not wish to retrieve a table variable. I want a single string each time the function is called. However there is a solution on there that might be a good start. Commented May 20, 2010 at 9:26

3 Answers 3

4

If you want a user-defined function to do this, this should work. Not that pretty, but...

CREATE FUNCTION dbo.SplitStringPart (
    @input nvarchar(MAX),
    @separator nvarchar(10),
    @index int
) RETURNS nvarchar(MAX)
BEGIN

DECLARE @counter int,
        @position int,
        @oldposition int,
        @separatorlength int,
        @result nvarchar(MAX)

SET @separatorlength = DATALENGTH(@separator) / 2
IF @separatorlength = 0 RETURN NULL

SET @result = NULL

SET @counter = 1
SET @position = -2

WHILE (@counter <= @index)
BEGIN

    SET @oldposition = @position
    SET @position = CHARINDEX(@separator, @input, @position + 1)
    IF @position = 0 AND @counter < @index
    BEGIN
        SET @oldposition = 0
        BREAK
    END
    SET @counter = @counter + 1

END

IF @oldposition = 0 AND @position = 0
    RETURN NULL
ELSE IF @oldposition < 0
BEGIN
    IF @position = 0 AND @index = 1
        SET @result = @input
    ELSE
        SET @result = SUBSTRING(@input, 0, @position)
END
ELSE IF @position <= 0
    SET @result = SUBSTRING(@input, @oldposition + @separatorlength, LEN(@input) - @oldposition - @separatorlength)
ELSE
    SET @result = SUBSTRING(@input, @oldposition + @separatorlength, @position - @oldposition - @separatorlength)

RETURN @result

END
GO
Sign up to request clarification or add additional context in comments.

1 Comment

It does break when the string only has 1 part and i ask for part 2 though ... not ideal.
1

It's not pretty, but add this to you SQL statement and it should work:

CASE 
WHEN charindex(' ', substring(AddressBlock, (charindex(' ', AddressBlock) + 1), len(AddressBlock))) > 0 THEN substring(AddressBlock, (charindex(' ', AddressBlock) + 1), charindex(' ', substring(AddressBlock, (charindex(' ', AddressBlock) + 1), len(AddressBlock))) - 1)
ELSE substring(AddressBlock, (charindex(' ', AddressBlock) + 1), len(AddressBlock))    
END AS 'Address 1', 
CASE WHEN charindex(' ', substring(AddressBlock, (charindex(' ', AddressBlock) + 1), len(AddressBlock))) > 0 THEN substring(AddressBlock, charindex(' ', AddressBlock) + charindex(' ', substring(AddressBlock, (charindex(' ', AddressBlock) + 1), len(AddressBlock))) + 1, Len(AddressBlock))
ELSE ''
END AS 'Address 2'

3 Comments

Doesn't this look for a single char on which to perform a split? I need to split on a string value (eg ", ") ... interesting though ...
This looks up the string value within the existing column and strips out everything up to the string value. So, change the charindex(' ' to charindex(',' if you want comma seperated.
It wasn't exactly what I asked for but a good effort so you got my vote :)
0

Here is my version of the answer. This is MUCH faster and robust. No need to fuss around with substrings, charindex, etc.

CREATE FUNCTION [dbo].[SplitArray]
(
    @RowToSplit nvarchar(MAX),
    @Delimeter nvarchar(MAX)
)  
RETURNS @RtnValue table (ID bigint IDENTITY, Data nvarchar(MAX)) 
AS  
BEGIN 
    DECLARE @xml xml
    SET @xml = '<field>' + REPLACE(@RowToSplit, @Delimeter, '</field><field>') + '</field>'
    INSERT INTO @RtnValue(data)
    SELECT  tbl.c.value('.','nvarchar(max)')
    FROM @xml.nodes('/field') tbl(c)
    RETURN
END

You would simply use the resultant split values in a table, like this:

SELECT Data FROM dbo.SplitArray('this is great',' ')

This will return:

Data
============
this
is
great

2 Comments

So let me get this right ... To get a piece of a string you split it up then build a bigger string of xml, then parse that xml, then query it, and sql will do this faster ... What a weird tech SQL is if this true!
The xml is a binary object so it's not quite correct. Run this with query analyser and you will see. Character index is slow as it is string based, using xml it is binary based.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.