Click here to Skip to main content
15,893,814 members
Please Sign up or sign in to vote.
1.00/5 (1 vote)
See more:
In my sql statement i only want to check the 2end last code in the comma seperated string. the amount of codes vary.

In this example i only what to check 'CX' against the code list.


when instr('AX,BX,CX,DX', CODE) > 0

What I have tried:

i have tried to search Google for a solution
Posted
Updated 29-Nov-18 18:10pm

I hope this will work even the code size vary
Declare @code varchar(20) ='AX,BX,CX,DX,XX'
;with cte as (
select 1 SNO,LEFT(@code,charindex(',',@code)-1)Code,RIGHT(@code,LEN(@code)-charindex(',',@code))RemCode
union all
select SNO+1,LEFT(RemCode,charindex(',',RemCode)-1),RIGHT(RemCode,LEN(RemCode)-charindex(',',RemCode))from cte where @code is Not null and charindex(',',RemCode)>0
)select Code from cte where SNO=(select max(SNO) from cte)
 
Share this answer
 
Comments
CHill60 30-Nov-18 7:35am    
Did you know you can use the "Improve solution" link to add information to your original solution? That is better than posting another solution because it makes it clearer that you have rethought the scenario and shows your thought process - it's less confusing for readers.

However, reason for my vote of 4. This is quite an elegant solution when you delve into it. It works for varying numbers of items >= 2 (whereas my solution will actually fail if number of items = 2)

Personally I would have explained that the solution uses a Recursive Common Table expression to generate a sequence or list of most of the component parts in the original string (the last one is omitted because of the check and charindex(',',RemCode)>0. Each item is assigned a number in that CTE which represents its position in the string. You then just select the last item in the sequence to get the desired result.

In other words - you add more value if you explain how to got to a solution rather than just dumping the code
First off, SQL string handling is poor at best, so any design which stores CSV data in SQL columns has to be viewed with extreme scepticism - it's probably badly designed and should use a separate table with a foreign key back to the original instead.

There is no "nice" solution, but you can use this: Converting comma separated data in a column to rows for selection[^] Once you have teh data as a temporary table, you can select any item you need from it.

But I'd seriously consider redesigning the DB to get rid of the CSV data - this is only the first of probably many nasty problems it will cause.
 
Share this answer
 
Comments
Jesper Schlütter 16-Nov-18 6:49am    
Thank you for your answser.

The database is not the problem the CODE table does not have comma seperated data in it.
The comma seperated string comes from an XML message (which I have no control over) where i need to check if the 2nd last code in the string exists in the CODE table.
What you are going to want to do is to utilize a string splitting function. The easy way to do this is going to use multiple queries; the first to convert the string to rows, and the last to get the specific row.

SQL Server 2016 has this function built in, called STRING_SPLIT
STRING_SPLIT (Transact-SQL) | Microsoft Docs[^]
Other versions of SQL can have similar functions installed, some are better than the now native function. SQL Server Central has quite a few and documentation on testing of these.

This is a very quick and ugly routine that has the basics of what you want. Once understood this should be refactored.

I am leaving it unrefined so that you can see the basics of the operations that are needed which reinforces OriginalGriff's assertion that string functions just aren't SQLs forte.
You would be much better off working in C# or whatever language and converting this to an array, then you can just grab whatever value by index

SQL
DECLARE @ElementCount INT =0
DECLARE @CSV NVARCHAR(1000) = 'AX,BX,CX,DX'
DECLARE @DesiredValue NVARCHAR(100)

DECLARE @SplitTable TABLE(idx INT IDENTITY(1,1) NOT NULL, Element NVARCHAR(100))

INSERT @SplitTable SELECT val FROM STRING_SPLIT(@CSV, ',')
SET @ElementCount = @@RowCount

SELECT @DesiredValue = val FROM @SplitTable WHERE idx = @ElementCount -1 

PRINT @DesiredValue
 
Share this answer
 
What solution 3 was trying to do and an option if you have an earlier version of SQL than 2016 (but 2008 or above). Basically reverse the string and remove the (now) first item, returning the new first item reversed (back as it was)...
SQL
Declare @code varchar(20)='AX,BX,CX,DX,XX'
Declare @revCode varchar(20) = REVERSE(@code)
set @revCode  = SUBSTRING(@revCode, CHARINDEX(',',@revCode) + 1, LEN(@revCode))
set @revCode = REVERSE(LEFT(@revCode, CHARINDEX(',', @revCode) - 1))
select @revCode -- DX
But I'm with the others that have suggested doing this in the calling layer not SQL if at all possible.
 
Share this answer
 
Declare @code varchar(20)='AX,BX,CX,DX'
Declare @FirstRemCode varchar(20),@SecondRemCode varchar(20)
select @FirstRemCode=RIGHT(@code,LEN(@code)-charindex(',',@code))
select @SecondRemCode=RIGHT(@FirstRemCode,LEN(@FirstRemCode)-charindex(',',@FirstRemCode))
select LEFT(@SecondRemCode,charindex(',',@SecondRemCode)-1) Code
 
Share this answer
 
v2
Comments
CHill60 29-Nov-18 5:25am    
OP Said:the amount of codes vary.If I run your code with @code='AX,BX,CX,DX' then it returns CX as expected, but if I run it with @code = 'AX,BX,CX,DX,XX' it still returns CX instead of DX. In other words, your solution does not work

This content, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)



CodeProject, 20 Bay Street, 11th Floor Toronto, Ontario, Canada M5J 2N8 +1 (416) 849-8900