![Creative The name of the picture]()
Use Split String Table Value Function in a Select statement
I have a table from a third party source that I have no control over. Each address field contains the FULL address including postcode. Each address has a dynamic number of separate address fields included. I have got a Split() TVF that works in splitting the address fields into seperate rows. However, when I CROSS APPLY the TVF table back to the SELECT query it returns a row for each ro in the TVF table. How do I get it to return one row for the main table and separate COLUMNS from the rows in the TVF table?
Example of addresses supplied:
a. 1 The Street, The Locality, The Town, The County, The Postcode
b. 2 The Building, The Street, The Town, The Postcode
c. Floor 3, 3 The Street, The Locality, The Town, The County, The Postcode
The TVF returns these as one value per row using the ',' as a delimiter. I then need to join that data back to the original data as one column per address field.
This is my SELECT QUERY:
select DISTINCT TOP 5 ttp.ProjectID
,cac.ID
,cac1.Proprietor1Address1
--,CASE WHEN addr.ID = 1 THEN addr.Data END AS Address1
FROM ArdentTest.ardent.LRTitlesToProcess ttp
JOIN LandRegistryData.landreg.CommercialandCorporateOwnershipData cac
ON ttp.TitleNo = cac.TitleNumber
JOIN (SELECT TitleNumber
,Proprietor1Address1
FROM LandRegistryData.landreg.CommercialandCorporateOwnershipData
WHERE 1 = 1
AND ISNULL(Proprietor1Address1, '') <> '') cac1
ON ttp.TitleNo = cac1.TitleNumber
CROSS APPLY DBAdmin.resource.Split(cac1.Proprietor1Address1, ', ') addr
WHERE 1 = 1
AND ttp.DateLRRequestSent IS NULL
AND cac.ID IN (50764, 78800, 157089, 206049, 449112)
ORDER BY 1
Which produces the following results:
ProjectID ID Proprietor1Address1
1010 50764 Bridge House, 1 Walnut Tree Close, Guildford, Surrey GU1 4LZ
1010 78800 Bridge House, 1 Walnut Tree Close, Guildford, Surrey GU1 4LZ
1010 157089 Bridge House, 1 Walnut Tree Close, Guildford, Surrey GU1 4LZ
1010 206049 Bridge House, 1 Walnut Tree Close, Guildford, Surrey GU1 4LZ
1010 449112 Church House, Great Smith Street, London SW1P 3AZ
I need to use the rows from the function to add separate address columns to the result set and I cannot figure out how to do it.
2 Answers
2
If you can make some assumption like an address can contain max 10 parts. You can use this script. I used STRING_SPLIT instead of your split function.
DECLARE @Table TABLE (Id INT, Address VARCHAR(500))
INSERT INTO @Table VALUES
(1, '1 The Street, The Locality, The Town, The County, The Postcode'),
(2, '2 The Building, The Street, The Town, The Postcode'),
(3, 'Floor 3, 3 The Street, The Locality, The Town, The County, The Postcode')
SELECT * FROM @Table T
CROSS APPLY(
SELECT * FROM (SELECT ROW_NUMBER()OVER(ORDER BY (SELECT NULL)) RN, * FROM STRING_SPLIT(T.Address, ',')) SRC
PIVOT (MAX(value) FOR RN IN ([1],[2],[3],[4],[5],[6],[7],[8],[9],[10])) PVT
) X
Result:
Id Address 1 2 3 4 5 6 7 8 9 10
----------- -------------------------------------------------------------------------------- --------------------- --------------------- --------------------- --------------------- --------------------- --------------------- --------------------- --------------------- --------------------- ---------------------
1 1 The Street, The Locality, The Town, The County, The Postcode 1 The Street The Locality The Town The County The Postcode NULL NULL NULL NULL NULL
2 2 The Building, The Street, The Town, The Postcode 2 The Building The Street The Town The Postcode NULL NULL NULL NULL NULL NULL
3 Floor 3, 3 The Street, The Locality, The Town, The County, The Postcode Floor 3 3 The Street The Locality The Town The County The Postcode NULL NULL NULL NULL
STRING_SPLIT
DelimitedSplit8K
You can create an XML out of your concatenated string and address each part via index
--the table (thx Serkan, I copied your DDL)
DECLARE @Table TABLE (Id INT, Address VARCHAR(500))
INSERT INTO @Table VALUES
(1, '1 The Street, The Locality, The Town, The County, The Postcode'),
(2, '2 The Building, The Street, The Town, The Postcode'),
(3, 'Floor 3, 3 The Street, The Locality, The Town, The County, The Postcode');
--This query will return the parts one by one
WITH Splitted AS
(
SELECT *
,CAST('<x>' + REPLACE((SELECT [Address] AS [*] FOR XML PATH('')),',','</x><x>') + '</x>' AS XML) AsXml
FROM @Table
)
SELECT *
,AsXml.value('/x[1]','nvarchar(max)') AS Col1
,AsXml.value('/x[2]','nvarchar(max)') AS Col2
,AsXml.value('/x[3]','nvarchar(max)') AS Col3
,AsXml.value('/x[4]','nvarchar(max)') AS Col4
,AsXml.value('/x[5]','nvarchar(max)') AS Col5
,AsXml.value('/x[6]','nvarchar(max)') AS Col6
FROM Splitted
--the result
/*+----+----------------+--------------+--------------+--------------+--------------+--------------+
| ID | Col1 | Col2 | Col3 | Col4 | Col5 | Col6 |
+----+----------------+--------------+--------------+--------------+--------------+--------------+
| 1 | 1 The Street | The Locality | The Town | The County | The Postcode | NULL |
+----+----------------+--------------+--------------+--------------+--------------+--------------+
| 2 | 2 The Building | The Street | The Town | The Postcode | NULL | NULL |
+----+----------------+--------------+--------------+--------------+--------------+--------------+
| 3 | Floor 3 | 3 The Street | The Locality | The Town | The County | The Postcode |
+----+----------------+--------------+--------------+--------------+--------------+--------------+*/
--You might use REVERSE on all steps. This will bring the Postcode in the first place in all cases (as long as the postcode is the last element there)
REVERSE
WITH Splitted AS
(
SELECT *
,CAST('<x>' + REPLACE((SELECT REVERSE([Address]) AS [*] FOR XML PATH('')),',','</x><x>') + '</x>' AS XML) AsXml
FROM @Table
)
SELECT *
,REVERSE(AsXml.value('/x[1]','nvarchar(max)')) AS Col1
,REVERSE(AsXml.value('/x[2]','nvarchar(max)')) AS Col2
,REVERSE(AsXml.value('/x[3]','nvarchar(max)')) AS Col3
,REVERSE(AsXml.value('/x[4]','nvarchar(max)')) AS Col4
,REVERSE(AsXml.value('/x[5]','nvarchar(max)')) AS Col5
,REVERSE(AsXml.value('/x[6]','nvarchar(max)')) AS Col6
FROM Splitted;
--the result
/*+----+--------------+------------+------------+----------------+--------------+---------+
| ID | Col1 | Col2 | Col3 | Col4 | Col5 | Col6 |
+----+--------------+------------+------------+----------------+--------------+---------+
| 1 | The Postcode | The County | The Town | The Locality | 1 The Street | NULL |
+----+--------------+------------+------------+----------------+--------------+---------+
| 2 | The Postcode | The Town | The Street | 2 The Building | NULL | NULL |
+----+--------------+------------+------------+----------------+--------------+---------+
| 3 | The Postcode | The County | The Town | The Locality | 3 The Street | Floor 3 |
+----+--------------+------------+------------+----------------+--------------+---------+*/
By clicking "Post Your Answer", you acknowledge that you have read our updated terms of service, privacy policy and cookie policy, and that your continued use of the website is subject to these policies.
You cannot write a query that will return an unknown number of columns. Every query always produces a result set with a fixed "shape" - the number of columns, their names and their types.
– Damien_The_Unbeliever
4 hours ago