Rob Horton is the Executive Director of Strategy and Marketing at ThreeWill. His experience includes over 25 years of leading software architecture, design, and development focusing on support tools, automation, and e-commerce for large corporations and his own small businesses.
Introduction
While working on enhancing our Jive Migration utilities, we found ourselves trying to select a specific string segment within JSON content stored in an Azure SQL migration database. We needed to split a string and select the last string segment, something like a Last() method. Unfortunately, this functionality isn’t built-in to SQL.
The Alternatives
The team first looked at reversing the string, finding the first index of the separating character, then reversing the string back to pull the last segment. This approach worked but lacked some flexibility in selecting a specific string segment.
A more flexible alternative would be to use the STRING_SPLIT() and ROW_NUMBER() functions. First, we’ll look at splitting a string and selecting the first (aka “First()”) string segment. The STRING_SPLIT() function returns a single-column table whose rows are the substrings. Let’s start with the following string:
[bash]DECLARE@mystring NVARCHAR(100)=’one two three four five six seven eight nine ten’;[/bash]
The following statement uses the SPLIT_STRING() function to split the string at every space:
[bash]SELECT value
FROM STRING_SPLIT(@mystring,’ ‘);[/bash]
And returns the following results:
[bash]value
———
one
two
three
four
five
six
seven
eight
nine
ten[/bash]
Selecting the First String Segment
To get the first string segment, we can simply take the first row using the “top 1” SQL statement shown here:
[bash]SELECT TOP 1 value
FROM STRING_SPLIT(@mystring,’ ‘);[/bash]
Which has the following result:
[bash]value
———
one[/bash]
Selecting the Last String Segment
Now that we’re able to select the first string segment of a split string, let’s move on to selecting the last (aka “Last()”) string segment. Our first thought may be to sort the STRING_SPLIT() function results in descending order and select the first row. Unfortunately, that won’t work because the result is an alphabetized list of our segmented string, shown here:
[bash]value
———
two
three
ten
six
seven
one
nine
four
five
eight[/bash]
Instead, we’ll need to add another value to each row so that we can sort the table by row number. We’ll create a new column called “n” to represent the row number. We’ll use the ROW_NUMBER() function and the OVER clause to populate the column as shown below:
[bash]SELECT value, n = ROW_NUMBER() OVER(ORDERBY (SELECT1))
FROM STRING_SPLIT(@mystring,’ ‘);[/bash]
Which has the following results:
[bash]value n
——— ———
one 1
two 2
three 3
four 4
five 5
six 6
seven 7
eight 8
nine 9
ten 10
[/bash]
Now we can sort the table by descending row number and take the top 1 row to get our last string as shown here:
[bash]SELECT TOP 1 value, n = ROW_NUMBER() OVER(ORDER BY (SELECT1))
FROM STRING_SPLIT(@mystring,’ ‘)
ORDER BY n DESC;[/bash]
Which has the following result:
[bash]value n
——— ———
ten 10[/bash]
Selecting a Specific String Segment
Finally, there may be situations where you need to take a specific string segment from the original split string that is neither first nor last. To take the nth string segment, we’ll need to first take the top n rows. Then we’ll need to reverse the row order and select the first row from the reversed table. This will result the selecting the nthstring segment. The following statement demonstrates this query:
[bash]SELECT TOP 1 value, n
FROM (
SELECT TOP 7 value, n = ROW_NUMBER() OVER(ORDER BY (SELECT 1))
FROM STRING_SPLIT(@mystring,’ ‘)) as my list
ORDER BY n DESC[/bash]
Which, in this example, results in selecting the 7thstring segment:
[bash]value n
——— ———
seven 7[/bash]
Conclusion
Although SQL doesn’t have built in functions for selecting the First(), Last() and nthstring segment from a longer string, were able to recreate this functionality using the STRING_SPLIT() and ROW_NUMBER() functions along with the OVER clause. If you thought this post was helpful, check out our other posts in Application Development.
1 Comment
Kirk Liemohn
Great stuff!