Home > front end >  Extracting multiple values from string and ordering them
Extracting multiple values from string and ordering them

Time:12-20

I have values within a Notes field consisting of values such as this where abc represents different words:

Request Notes: VAR - abc abc abc abc abc

Unfortunately the design of how the data is stored is very poor, and I need to pull out the Note Type for each "Required Notes:" record. It also needs ordering from most recent to oldest (last part of the string to first part of the string).

CREATE TABLE #TestData
(
    ClientID int,
    Notes varchar(8000)
)
insert into #TestData
(
    ClientID,
    Notes
)
select
    1,
    'Request Notes: VAR - abc abc abc abc abc'
union all
select
    2,
    'Request Notes: OZR - abc abc abc abc abc Request Notes: ACC - abc abc abc abc abc Request Notes: TYU - abc abc abc abc abc'
union all
select
    3,
    'Request Notes: TYU - abc abc abc abc abc Request Notes: VAR - abc abc abc abc abc'

This is how I expect the output to be for the above examples:

--Expected Output

Client ID       Type    Order
1               VAR     1
2               TYU     1
2               ACC     2
2               OZR     3
3               VAR     1
3               TYU     2

I have this together so far which extracts OZR, but I'm stumped on how to get the others and order the list into the expected output above.

DECLARE @Text varchar(500) = 'Request Notes: OZR - abc abc abc abc abc Request Notes: ACC - abc abc abc abc abc Request Notes: TYU - abc abc abc abc abc'

SELECT TRIM(REPLACE(REPLACE(SUBSTRING(@Text, CHARINDEX(':', @Text), CHARINDEX('-',@text) - CHARINDEX(':', @Text)   Len('-')),':',''),'-',''))

CodePudding user response:

You can use openjson to extract your data as an array and filter:

select d.ClientId, n.*
from #testdata d
cross apply (
  select 
    Left(j.[value],3) [Type],
    Row_Number() over(order by Convert(int,j.[key])) [Order] 
  from OpenJson(Concat('["',replace(notes,'Notes: ', '","'),'"]')) j
  where j.[value] != 'Request'
 )n;

Example Fiddle

CodePudding user response:

Here's a recursive CTE version. It splits the string based on finding "Request Notes:" then does a left/right combo to extract the 3 letter code. It iterates the order as it builds. Then you select from the CTE and only take rows where there's some NotesRemainder:

;
WITH CTESplit
AS (
    SELECT ClientID,
           RIGHT(LEFT(Notes, CHARINDEX('Request Notes:', Notes)   17), 3) AS NotesPart,
           RIGHT(Notes, LEN(Notes) - CHARINDEX('Request Notes:', Notes) - 17) AS NotesRemainder,
           1 AS [Order]
    FROM #TestData
    WHERE Notes IS NOT NULL AND CHARINDEX('Request Notes:', Notes) > 0
    UNION ALL
    SELECT CTESplit.ClientID,
           RIGHT(LEFT(CTESplit.NotesRemainder, CHARINDEX('Request Notes:', CTESplit.NotesRemainder)   17), 3),
           RIGHT(CTESplit.NotesRemainder, LEN(CTESplit.NotesRemainder) - CHARINDEX('Request Notes:', CTESplit.NotesRemainder)),
           CTESplit.[Order]   1
    FROM CTESplit
    WHERE CTESplit.NotesRemainder IS NOT NULL AND CHARINDEX('Request Notes:', CTESplit.NotesRemainder) > 0
    UNION ALL
    SELECT CTESplit.ClientID,
           RIGHT(LEFT(CTESplit.NotesRemainder, CHARINDEX('Request Notes:', CTESplit.NotesRemainder)   17), 3),
           NULL,
           CTESplit.[Order]   1
    FROM CTESplit
    WHERE CTESplit.NotesRemainder IS NOT NULL AND CHARINDEX('Request Notes:', CTESplit.NotesRemainder) = 0
)
SELECT CTESplit.ClientID,
       CTESplit.NotesPart AS Type,
       CTESplit.[Order]
FROM CTESplit
WHERE CTESplit.NotesRemainder IS NOT NULL
ORDER BY CTESplit.ClientID,
         CTESplit.[Order] DESC;
  • Related