{"id":37133,"date":"2024-08-22T06:38:28","date_gmt":"2024-08-21T20:38:28","guid":{"rendered":"https:\/\/database.guide\/?p=37133"},"modified":"2024-08-22T06:38:30","modified_gmt":"2024-08-21T20:38:30","slug":"some-handy-t-sql-string-manipulation-techniques","status":"publish","type":"post","link":"https:\/\/database.guide\/some-handy-t-sql-string-manipulation-techniques\/","title":{"rendered":"Some Handy T-SQL String Manipulation Techniques"},"content":{"rendered":"\n<p class=\"\">Transact-SQL (<a href=\"https:\/\/database.guide\/what-is-t-sql\/\" data-type=\"post\" data-id=\"1755\">T-SQL<\/a>) offers a nice set of functions and methods for manipulating strings. Let&#8217;s look at some handy techniques that can help us work more efficiently with string data in <a href=\"https:\/\/database.guide\/what-is-sql-server\/\" data-type=\"post\" data-id=\"657\">SQL Server<\/a>.<\/p>\n\n\n\n<!--more-->\n\n\n\n<h2 class=\"wp-block-heading\">String Splitting with <code>STRING_SPLIT()<\/code><\/h2>\n\n\n\n<p class=\"\">The <a href=\"https:\/\/database.guide\/understanding-the-string_split-function-in-sql-server\/\" data-type=\"post\" data-id=\"33492\"><code>STRING_SPLIT()<\/code> function<\/a>, introduced in SQL Server 2016, provides an efficient way to split strings based on a delimiter:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>SELECT value\nFROM STRING_SPLIT('apple,banana,cherry', ',');<\/code><\/pre>\n\n\n\n<p class=\"\">Result:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">value <br>------<br>apple <br>banana<br>cherry<br><br>3 row(s) returned<\/pre>\n\n\n\n<p class=\"\">This function returns a table of strings, making it easy to use in <code><a href=\"https:\/\/database.guide\/sql-joins-tutorial\/\" data-type=\"post\" data-id=\"11436\">JOIN<\/a><\/code>s or other set-based operations.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">String Aggregation with <code>STRING_AGG()<\/code><\/h2>\n\n\n\n<p class=\"\">The <a href=\"https:\/\/database.guide\/the-sql-server-equivalent-to-group_concat\/\" data-type=\"post\" data-id=\"2233\"><code>STRING_AGG()<\/code> function<\/a>, available from SQL Server 2017 onwards, allows for efficient string concatenation:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>SELECT STRING_AGG(Name, ', ') AS ProductList FROM Product;<\/code><\/pre>\n\n\n\n<p class=\"\">Example result:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">ProductList                                                                                                                         <br>------------------------------------------------------------------------------------------------------------------------------------<br>Mountain Bike, Road Bike, Helmet, Water Bottle, Bike Pump, Cycling Shorts, Bike Light Set, Cycling Gloves, Bike Lock, Cycling Jersey<br><br>1 row(s) returned<\/pre>\n\n\n\n<p class=\"\">This function can also be used with <code>ORDER BY<\/code> for sorted concatenation. To do this, use the <code>WITHIN GROUP<\/code> clause:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>SELECT \n    STRING_AGG(Name, ', ') WITHIN GROUP ( ORDER BY Name ) AS ProductList \nFROM Product;<\/code><\/pre>\n\n\n\n<p class=\"\">Example result:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">ProductList                                                                                                                         <br>------------------------------------------------------------------------------------------------------------------------------------<br>Bike Light Set, Bike Lock, Bike Pump, Cycling Gloves, Cycling Jersey, Cycling Shorts, Helmet, Mountain Bike, Road Bike, Water Bottle<br><br>1 row(s) returned<\/pre>\n\n\n\n<h2 class=\"wp-block-heading\">Pattern Matching with <code>LIKE<\/code><\/h2>\n\n\n\n<p class=\"\">Complex pattern matching can be achieved using the <a href=\"https:\/\/database.guide\/sql-like-operator-for-beginners\/\" data-type=\"post\" data-id=\"11727\"><code>LIKE<\/code> operator<\/a> with wildcards:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>SELECT *\nFROM Customers\nWHERE LastName LIKE '&#91;AEIOU]%';<\/code><\/pre>\n\n\n\n<p class=\"\">This returns customers where <code>LastName<\/code> starts with a vowel.<\/p>\n\n\n\n<p class=\"\">Here&#8217;s another example:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>SELECT ProductName, Description\nFROM Products\nWHERE Description LIKE '%organic%'\n   OR Description LIKE '%natural%'\n   OR Description LIKE '%eco-friendly%';<\/code><\/pre>\n\n\n\n<p class=\"\">This query retrieves products where the description contains any of the words <code>organic<\/code>, <code>natural<\/code>, or <code>eco-friendly<\/code>. The <code>%<\/code> wildcard allows for any characters before or after the specified words.<\/p>\n\n\n\n<p class=\"\">One more example.<\/p>\n\n\n\n<p class=\"\">Suppose we have the following table:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">EmployeeID  Email                           <br>----------  --------------------------------<br>1           john_doe@company.co.za          <br>2           jane.smith@techinc.org.au       <br>3           mike.j@datasoft.net             <br>4           sarah.w@hrgroup.co.uk           <br>5           robert_brown@finance-corp.com.au<br>6           emily.davis@salesforce.io       <br>7           david.m@techsupport.co.nz       <br>8           lisa.wilson@marketpro.com.au    <br>9           tom.anderson@globalfin.biz   <\/pre>\n\n\n\n<p class=\"\">Here&#8217;s a query that uses the <code>LIKE<\/code> operator to filter the <code>Email<\/code> column by a certain pattern:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>SELECT EmployeeID, Email\nFROM Employees\nWHERE Email LIKE '%&#91;a-z]%&#91;.]&#91;a-z]%@%&#91;.]%&#91;.]%';<\/code><\/pre>\n\n\n\n<p class=\"\">Example result:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">EmployeeID  Email                       <br>----------  ----------------------------<br>2           jane.smith@techinc.org.au   <br>4           sarah.w@hrgroup.co.uk       <br>7           david.m@techsupport.co.nz   <br>8           lisa.wilson@marketpro.com.au<\/pre>\n\n\n\n<h2 class=\"wp-block-heading\">Substring Extraction with <code>CHARINDEX()<\/code> and <code>SUBSTRING()<\/code><\/h2>\n\n\n\n<p class=\"\">Combine <code><a href=\"https:\/\/database.guide\/how-the-charindex-function-works-in-sql-server-t-sql\/\" data-type=\"post\" data-id=\"3947\">CHARINDEX()<\/a><\/code> and <code><a href=\"https:\/\/database.guide\/how-to-return-a-substring-from-a-string-in-sql-server-using-substring-function\/\" data-type=\"post\" data-id=\"1809\">SUBSTRING()<\/a><\/code> for flexible text extraction:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>DECLARE @email VARCHAR(100) = 'user@example.com';\nSELECT SUBSTRING(@email, 1, CHARINDEX('@', @email) - 1);<\/code><\/pre>\n\n\n\n<p class=\"\">Here it is when run against the <code>Employees<\/code> table from the previous example:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>SELECT \n    SUBSTRING(Email, 1, CHARINDEX('@', Email) - 1) AS UserName \nFROM Employees;<\/code><\/pre>\n\n\n\n<p class=\"\">Result:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">UserName    <br>------------<br>john_doe    <br>jane.smith  <br>mike.j      <br>sarah.w     <br>robert_brown<br>emily.davis <br>david.m     <br>lisa.wilson <br>tom.anderson<\/pre>\n\n\n\n<h2 class=\"wp-block-heading\">Advanced Parsing with <code>PARSENAME()<\/code><\/h2>\n\n\n\n<p class=\"\"><code><a href=\"https:\/\/database.guide\/use-parsename-to-return-part-of-an-object-name-in-sql-server\/\" data-type=\"post\" data-id=\"6818\">PARSENAME()<\/a><\/code> is traditionally used for parsing object names, but it can be repurposed for general string parsing:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>SELECT PARSENAME('192.168.0.1', 4);<\/code><\/pre>\n\n\n\n<p class=\"\">Result:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">192<\/pre>\n\n\n\n<p class=\"\">This technique works well for strings with up to four period-separated parts. <code>PARSENAME()<\/code> works backwards, and so that&#8217;s why <code>4<\/code> returned the first octet.<\/p>\n\n\n\n<p class=\"\">If the separators are something other than dots, we can use <code>REPLACE()<\/code> to change them to the relevant separator:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>SELECT PARSENAME(REPLACE('HWP-435-9002-98', '-', '.'), 2);<\/code><\/pre>\n\n\n\n<p class=\"\">Result:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">9002<\/pre>\n\n\n\n<p class=\"\">If you don&#8217;t like the fact that <code>PARSENAME()<\/code> works backwards, there&#8217;s always the option of using the <a href=\"https:\/\/database.guide\/how-to-return-a-string-in-reverse-order-using-sql-server\/\" data-type=\"post\" data-id=\"1903\"><code>REVERSE()<\/code> function<\/a> in a couple of places to change the order around:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>SELECT REVERSE(PARSENAME(REPLACE(REVERSE('HWP-435-9002-98'), '-', '.'), 2));<\/code><\/pre>\n\n\n\n<p class=\"\">Result:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">435<\/pre>\n\n\n\n<p class=\"\">Here, the inner <code>REVERSE()<\/code> would&#8217;ve resulted in <code>435<\/code> being returned as <code>534<\/code> (reverse order), and so the outer <code>REVERSE()<\/code> reverses that again to its original order.<\/p>\n\n\n\n<p class=\"\">Bearing in mind that the <code>PARSENAME()<\/code> wasn&#8217;t really designed for this type of string splitting (it is mainly for returning a specified part of an object name), there are usually other ways to do this type of thing (and let&#8217;s not forget our first example that uses the <code>STRING_SPLIT()<\/code> function). Here&#8217;s an <a href=\"https:\/\/forums.sqlteam.com\/t\/is-parsename-safe-for-general-parsing-and-splitting\/5990\" target=\"_blank\" rel=\"noreferrer noopener\">interesting discussion over at SQLTeam.com<\/a> about the pros and cons of using <code>PARSENAME()<\/code> for string splitting along with some alternatives.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Fuzzy Matching with <code>SOUNDEX()<\/code><\/h2>\n\n\n\n<p class=\"\">The <code><a href=\"https:\/\/database.guide\/how-the-sql-server-soundex-function-works\/\" data-type=\"post\" data-id=\"2026\">SOUNDEX()<\/a><\/code> function can be used for phonetic matching:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>SELECT * \nFROM Employees \nWHERE SOUNDEX(LastName) = SOUNDEX('Smith');<\/code><\/pre>\n\n\n\n<p class=\"\">Result:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">EmployeeID  FirstName  LastName  Email                      Department<br>----------  ---------  --------  -------------------------  ----------<br>2           Jane       Smith     jane.smith@techinc.org.au  Marketing <br>10          Sasha      Smyth     sasha_smyth@kiwi.co.nz     Sales     <br>11          Rod        Smythe    rod.s@.hot.studio            Sales     <\/pre>\n\n\n\n<p class=\"\">We can see that although we only entered <code>Smith<\/code>, the <code>SOUNDEX()<\/code> function ensured that it also matched other names that sound similar to <code>Smith<\/code>.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Conclusion<\/h2>\n\n\n\n<p class=\"\">These handy T-SQL string manipulation techniques can significantly enhance our ability to work with text data in SQL Server. <\/p>\n\n\n\n<p class=\"\">Remember to consider performance implications when working with large datasets, and always test thoroughly in a non-production environment before implementing these techniques in production systems.<\/p>\n\n\n\n<p class=\"\"><\/p>\n\n\n\n<p class=\"\"><\/p>\n","protected":false},"excerpt":{"rendered":"<p>Transact-SQL (T-SQL) offers a nice set of functions and methods for manipulating strings. Let&#8217;s look at some handy techniques that can help us work more efficiently with string data in SQL Server.<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"closed","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[5],"tags":[10,77,84,61],"class_list":["post-37133","post","type-post","status-publish","format-standard","hentry","category-sql-server","tag-how-to","tag-mssql","tag-string","tag-t-sql"],"_links":{"self":[{"href":"https:\/\/database.guide\/wp-json\/wp\/v2\/posts\/37133","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/database.guide\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/database.guide\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/database.guide\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/database.guide\/wp-json\/wp\/v2\/comments?post=37133"}],"version-history":[{"count":5,"href":"https:\/\/database.guide\/wp-json\/wp\/v2\/posts\/37133\/revisions"}],"predecessor-version":[{"id":38593,"href":"https:\/\/database.guide\/wp-json\/wp\/v2\/posts\/37133\/revisions\/38593"}],"wp:attachment":[{"href":"https:\/\/database.guide\/wp-json\/wp\/v2\/media?parent=37133"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/database.guide\/wp-json\/wp\/v2\/categories?post=37133"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/database.guide\/wp-json\/wp\/v2\/tags?post=37133"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}