8

I have a database field that contains address information stored as multi-line strings.

88 Park View
Hemmingdale
London

Could anyone tell me the best way to get line 1, line 2 & line 3 as distinct fields in a select statement?

Regards Richard

5 Answers 5

7

Try something like this? Mind you this is bit vulnerable

DECLARE @S VARCHAR(500), @Query VARCHAR(1000)
SELECT @S='88 Park View
           Hemmingdale
           London'

SELECT @Query=''''+ REPLACE(@S, CHAR(13),''',''')+''''
EXEC('SELECT '+@Query)

Results

88 Park View | Hemmingdale | London
Sign up to request clarification or add additional context in comments.

Comments

5

Here is a solution I came up with using a CTE to recursively iterate a table of values, and split them out by new line CHAR(13), and then use a PIVOT to show the results. You can expand this to additional columns (more than 5) just by adding to these to the PIVOT.

DECLARE @Table AS TABLE(ID int, SomeText VARCHAR(MAX))

INSERT INTO @Table VALUES(1, '88 Park View
Hemmingdale
London')

INSERT INTO @Table VALUES(2, '100 Main Street
Hemmingdale
London')

INSERT INTO @Table VALUES(3, '123 6th Street
Appt. B
Hemmingdale
London')

;WITH SplitValues (ID, OriginalValue, SplitValue, Level)
AS
(
    SELECT  ID, SomeText, CAST('' AS VARCHAR(MAX)), 0 FROM @Table

    UNION ALL

    SELECT  ID
    ,   SUBSTRING(OriginalValue, CASE WHEN CHARINDEX(CHAR(13), OriginalValue) = 0 THEN LEN(OriginalValue) + 1 ELSE CHARINDEX(CHAR(13), OriginalValue) + 2 END, LEN(OriginalValue))
    ,   SUBSTRING(OriginalValue, 0, CASE WHEN CHARINDEX(CHAR(13), OriginalValue) = 0 THEN LEN(OriginalValue) + 1 ELSE CHARINDEX(CHAR(13), OriginalValue) END)
    ,   Level + 1
    FROM    SplitValues
    WHERE   LEN(SplitValues.OriginalValue) > 0
)

SELECT  ID, [1] AS Level1, [2] AS Level2, [3] AS Level3, [4] AS Level4, [5] AS Level5
FROM    (
    SELECT  ID, Level, SplitValue
    FROM    SplitValues
    WHERE   Level > 0
    ) AS p
PIVOT   (MAX(SplitValue) FOR Level IN ([1], [2], [3], [4], [5])) AS pvt

Results:

ID          Level1               Level2               Level3               Level4               Level5
----------- -------------------- -------------------- -------------------- -------------------- --------------------
1           88 Park View         Hemmingdale          London               NULL                 NULL
2           100 Main Street      Hemmingdale          London               NULL                 NULL
3           123 6th Street       Appt. B              Hemmingdale          London               NULL

1 Comment

One of the best things I have come across on StackOverflow! I bow my head to a master.
0

Just for fun, updated with XML solution. This should handle '.' issue and can easily to extend to more lines.

DECLARE @xml XML , @S VARCHAR(500) = '88 Park View
Hemmingdale
London'

SET @xml  = CAST('<row><col>' + REPLACE(@S,CHAR(13),'</col><col>') + '</col></row>' AS XML)

SELECT  
     line.col.value('col[1]', 'varchar(1000)') AS line1
    ,line.col.value('col[2]', 'varchar(1000)') AS line2
    ,line.col.value('col[3]', 'varchar(1000)') AS line3
FROM    @xml.nodes('/row') AS line(col)

2 Comments

Clever, but what about "88 Park View St."?
@TimLehner, you are right. Maybe it's not a good idea to use '.' on address :)
0

I know this is horrible but this way you have the 3 lines in 3 columns called l1,l2 and l3:

declare @input nvarchar(max) =  'line 1' + CHAR(13) + CHAR(10) + 'line 2' + CHAR(13) + CHAR(10) + 'line 3' + CHAR(13) + CHAR(10) + 'line 4' + CHAR(13) + CHAR(10) + 'line 5'
declare @delimiter nvarchar(10) = CHAR(13) + CHAR(10)

declare @outtable table (id int primary key identity(1,1), data nvarchar(1000) )

declare @pos int = 1
declare @temp nvarchar(1000)

if substring( @input, 1, len(@delimiter) ) = @delimiter
begin
    set @input = substring(@input, 1+len(@delimiter), len(@input))
end

while @pos > 0
begin

    set @pos = patindex('%' + @delimiter + '%', @input)

    if @pos > 0
        set @temp = substring(@input, 1, @pos-1)
    else
        set @temp = @input

    insert into @outtable ( data ) values ( @temp )

    set @input = substring(@input, @pos+len(@delimiter), len(@input))

end

select
    top 1 ISNULL(a.data,'') as l1, ISNULL(b.data,'') as l2, ISNULL(c.data,'') as l3
from
    @outtable a
        left outer join @outtable b on b.id = 2
        left outer join @outtable c on c.id = 3

sqlfiddle here

Comments

0

It has been more than a decade and many things have been changed including the easiest way to do that in TSQL.

declare @data as nvarchar(max) = N'88 Park View
Hemmingdale
London';

select ordinal as LineNo_, value as perLine from string_split(@data, char(13),1);

Comments

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.