Hi @Debilon ,
Please try the following solution.
Notable points:
- 1st
CROSS APPLY
is tokenizing address via XML. - 2nd
CROSS APPLY
is retrieving last token via...r[last()]...
- 3rd
CROSS APPLY
is checking if the last token is on the predefined list of street types. -
TRIM()
function is used to trim a possible trailing dot.
SQL
-- DDL and sample data population, start
DECLARE @StreetName Table (ID INT IDENTITY PRIMARY KEY, StreetName VARCHAR(50));
INSERT INTO @StreetName (StreetName) VALUES
('S Chestnut St'),
('W 1st St'),
('W 21st St'),
('31st St'),
('Happyjack Rd'),
('Murray Rd'),
('N Mccue St'),
('Linda Vista Dr'),
('Reynolds St'),
('17 Mile Rd'),
('Center St'),
('N Mccue St'),
('Denny Way');
-- DDL and sample data population, end
DECLARE @separator CHAR(1) = SPACE(1);
SELECT t.*
, NewAddress = c.query('data(/root/r[position() le (last()-sql:column("y"))])').value('.', 'VARCHAR(50)')
, StPOS = IIF(y=1, x, NULL)
FROM @StreetName AS t
CROSS APPLY (SELECT TRY_CAST('<root><r>' +
REPLACE(StreetName, @separator, '</r><r>') +
'</r></root>' AS XML)) AS t1(c)
CROSS APPLY (SELECT c.value('(/root/r[last()]/text())[1]', 'VARCHAR(5)')) AS t2(x)
CROSS APPLY (SELECT IIF(TRIM('.' FROM x) IN ('DR', 'ST', 'AVE', 'AV', 'RD', 'LN', 'TR'),1,0)) AS t3(y);
Output
+----+----------------+-------------+-------+
| ID | StreetName | NewAddress | StPOS |
+----+----------------+-------------+-------+
| 1 | S Chestnut St | S Chestnut | St |
| 2 | W 1st St | W 1st | St |
| 3 | W 21st St | W 21st | St |
| 4 | 31st St | 31st | St |
| 5 | Happyjack Rd | Happyjack | Rd |
| 6 | Murray Rd | Murray | Rd |
| 7 | N Mccue St | N Mccue | St |
| 8 | Linda Vista Dr | Linda Vista | Dr |
| 9 | Reynolds St | Reynolds | St |
| 10 | 17 Mile Rd | 17 Mile | Rd |
| 11 | Center St | Center | St |
| 12 | N Mccue St | N Mccue | St |
| 13 | Denny Way | Denny Way | NULL |
+----+----------------+-------------+-------+
CData section
Here is a defense mechanism against XML special characters.