-1

I am using SQL Server 2017.

I have a Description column in my table which may contain multiple colors. I need to grab the last color that appears in the string. Is there way to order it per value that is parsed from the description column descending?

SELECT DISTINCT color   
FROM (VALUES ('Dove'), ('Frost')) t(Color)
WHERE 'jgkgh FROST tohjgkhg DOVE gfsgfgs' LIKE CONCAT('%', t.Color, '%') 
  AND t.Color IS NOT NULL 
marc_s
  • 732,580
  • 175
  • 1,330
  • 1,459
Discover
  • 33
  • 6
  • use string_Split() to parse out the description column into it's own rows with an ordinal and then get the max ordinal with a color inlist. https://learn.microsoft.com/en-us/sql/t-sql/functions/string-split-transact-sql?view=sql-server-ver15; then using that ordinal get the color. – xQbert Nov 18 '21 at 19:43
  • While asking a question, you need to provide a [minimal reproducible example](https://stackoverflow.com/help/minimal-reproducible-example): (1) DDL and sample data population, i.e. CREATE table(s) plus INSERT T-SQL statements. (2) What you need to do, i.e. logic and your code attempt implementation of it in T-SQL. (3) Desired output, based on the sample data in the #1 above. (4) Your SQL Server version (SELECT @@version;). – Yitzhak Khabinsky Nov 18 '21 at 21:16

4 Answers4

1

SELECT distinct color , charindex(' ' + reverse(color)+' ', ' ' + reverse('jgkgh FROST tohjgkhg DOVE gfsgfgs dove frost') + ' ') as rvrscharidx 
FROM (VALUES('Dove'),('Frost'))t(Color)
WHERE   'jgkgh FROST tohjgkhg DOVE gfsgfgs dove frost' LIKE CONCAT('%',t.Color,'%') AND t.Color IS NOT NULL 
order by rvrscharidx
lptr
  • 1
  • 2
  • 6
  • 16
0

UNTESTED: Uses table value function STRING_SPLIT()

WITH CTE AS (SELECT value 
FROM STRING_SPLIT('jgkgh FROST tohjgkhg DOVE gfsgfgs', ' ', 1))

SELECT TOP 1 *
FROM CTE 
WHERE VALUE in ('Dove', 'Frost')
ORDER BY Ordinal Desc

Reference Example:

SELECT value FROM STRING_SPLIT('Lorem ipsum dolor sit amet.', ' ', 1);

https://learn.microsoft.com/en-us/sql/t-sql/functions/string-split-transact-sql?view=sql-server-ver15

xQbert
  • 34,733
  • 2
  • 41
  • 62
  • 1
    String_split does **not** guarantee order. The doc is unfortunately confusing since it includes syntax that is valid for only some versions of sql server. – SMor Nov 18 '21 at 20:43
  • The more you know! https://dba.stackexchange.com/questions/207274/string-split-and-ordered-results/233480 I had no idea. so JSON approach may work better... https://stackoverflow.com/questions/60129782/result-order-of-string-split – xQbert Nov 18 '21 at 20:54
  • As an alternative: XML/XQuery. – Yitzhak Khabinsky Nov 18 '21 at 21:02
  • Directly from the official documentation: "...The enable_ordinal argument and ordinal output column are currently only supported in Azure SQL Database, Azure SQL Managed Instance, and Azure Synapse Analytics (serverless SQL pool only)...." – Yitzhak Khabinsky Nov 18 '21 at 21:19
  • FYI the *enable_ordinal* option is supposedly in the SQL Server 2022 release. – Stu Nov 18 '21 at 21:22
0

Please try the following solution.

It is using XML/XQuery. Their data model is based on ordered sequences. Exactly what we need.

  1. CROSS APPLY converts Description column into XML data type.
  2. To get the last token, we are using the following XPath predicate: /root/r[last()]
  3. To sort colors, we are using FLWOR expression with the order by data($x) descending clause.

SQL

-- DDL and sample data population, start
DECLARE @tbl TABLE (ID INT IDENTITY PRIMARY KEY, [Description] VARCHAR(255));
INSERT INTO @tbl ([Description]) VALUES
('Blue Black Red'),
('Cyan Green White');
-- DDL and sample data population, end

DECLARE @separator CHAR(1) = SPACE(1);

-- without sorting
SELECT t.*
    , c.value('(/root/r[last()]/text())[1]', 'VARCHAR(20)') AS lastColor
FROM @tbl AS t
CROSS APPLY (SELECT TRY_CAST('<root><r><![CDATA[' + 
      REPLACE([Description], @separator, ']]></r><r><![CDATA[') + 
      ']]></r></root>' AS XML)) AS tab(c);

-- with sorting
SELECT t.*
    , c.value('(/root/r[last()]/text())[1]', 'VARCHAR(20)') AS lastColor
    , c
FROM @tbl AS t
CROSS APPLY (SELECT TRY_CAST('<root><r><![CDATA[' + 
      REPLACE([Description], @separator, ']]></r><r><![CDATA[') + 
      ']]></r></root>' AS XML).query('<root>
        {
            for $x in /root/r
            order by data($x) descending
            return $x
        }
      </root>
      ')) AS tab(c);

Output without sorting

+----+------------------+-----------+
| ID |   Description    | lastColor |
+----+------------------+-----------+
|  1 | Blue Black Red   | Red       |
|  2 | Cyan Green White | White     |
+----+------------------+-----------+

Output with sorting

+----+------------------+-----------+
| ID |   Description    | lastColor |
+----+------------------+-----------+
|  1 | Blue Black Red   | Black     |
|  2 | Cyan Green White | Cyan      |
+----+------------------+-----------+
Yitzhak Khabinsky
  • 18,471
  • 2
  • 15
  • 21
0

The simplest and fastest way to solve this:

-- DDL and sample data population, start DECLARE @tbl TABLE (ID INT IDENTITY PRIMARY KEY, [Description] VARCHAR(255)); INSERT INTO @tbl ([Description]) VALUES ('Red Blue Black'), ('White Green'); -- DDL and sample data population, end

DECLARE @separator CHAR(1) = SPACE(1);

SELECT t.*, LastColor = RIGHT(t.Description,CHARINDEX(SPACE(1),REVERSE(t.Description)))
FROM @tbl AS t;

Returns:

ID   Description                                                                                                                                                                                                                                                     LastColor
---- ------------------
1    Red Blue Black                                                                                                                                                                                                                                                   Black
2    White Green                                                                                                                                                                                                                                                      Green
Alan Burstein
  • 7,770
  • 1
  • 15
  • 18