Split String Returning only first value - sql-server

My split string code is only returning the first value for some reason. I cannot figure this out so any help would be appreciated. I am using the following.
declare #CYEnd varchar(4) = '2015, 2016, 2017'
SELECT * FROM vwRMSGrantsSpending
WHERE CYEnd IN (select ltrim(item) from dbo.SplitStringList(#CYEnd, ','))
This should be returning 2015, 2016, and 2017. But it is only returning 2015.
Here is dbo.SplitStringList
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
ALTER FUNCTION [dbo].[SplitStringList](#ListString nvarchar(max), #delim
varchar(2) = ',')
returns #vals table (Item nvarchar(60))
as
begin
declare #CurLoc int, #Item nvarchar(60)
while len(#ListString) > 0
begin
set #CurLoc = charindex(#delim, #ListString, 1)
if #CurLoc = 0
begin
set #Item = #ListString
set #Item = Ltrim(RTrim(#Item))
set #ListString = ''
end
else
begin
set #Item = left(#ListString, #CurLoc - 1)
set #Item = Ltrim(RTrim(#Item))
set #ListString = substring(#ListString, #CurLoc + 1,
Len(#ListString) - #CurLoc)
end
insert into #vals (Item) values (#Item)
end
return
end

The problem is that you defined the varchar too small.
declare #CYEnd varchar(4) = '2015, 2016, 2017'
If you run this PRINT #CYEnd after the declare you will see that the variable is only equal to 2015.
Make that variable bigger and it works.

Related

Create function that returns table doesn't work syntax error? SQL

Hello I need to make a sql request that takes multi parameters in a 'WHERE (abc IN #par1, #par2 ....'
To do so, I found some solutions that use a sql function. I tried to use it without any success.
I'm working on workbench and this is my function code.
CREATE function MultiStringToTable (InStr VARCHAR(255))
RETURNS #TempTab TABLE(
id nvarchar(255) not null
)
AS
BEGIN
-- Ensure input ends with comma
SET #InStr = REPLACE(#InStr + ',', ',,', ',');
DECLARE #SP INT;
DECLARE #VALEUR VARCHAR(1000);
WHILE PATINDEX('%,%', #INSTR ) <> 0
SET #SP = PATINDEX('%,%',#INSTR);
SET #VALEUR = LEFT(#INSTR , #SP - 1);
SET #INSTR = STUFF(#INSTR, 1, #SP, '');
INSERT INTO #TempTab(id) VALUES (#VALEUR);
END;
RETURN;
end;
It causes problem on the '#TempTab'.
Thanks for help.
First - Artem beat me to it but the correct code is:
CREATE function MultiStringToTable (#InStr VARCHAR(255))
RETURNS #TempTab TABLE(id nvarchar(255) not null)
AS
BEGIN
-- Ensure input ends with comma
SET #InStr = REPLACE(#InStr + ',', ',,', ',');
DECLARE #SP INT;
DECLARE #VALEUR VARCHAR(1000);
WHILE PATINDEX('%,%', #INSTR ) <> 0
BEGIN
SET #SP = PATINDEX('%,%',#INSTR);
SET #VALEUR = LEFT(#INSTR , #SP - 1);
SET #INSTR = STUFF(#INSTR, 1, #SP, '');
INSERT INTO #TempTab(id) VALUES (#VALEUR);
END;
RETURN;
END;
GO
That said - ^^^ This is going to be horribly slow. For what you are doing you can use STRING_SPLIT.
DECLARE #instr VARCHAR(8000) = 'abc,,xxx,yyy,,z';
SELECT split.* FROM STRING_SPLIT(#instr,',') AS split WHERE split.[value] > '';
Done. Better yet, you can have any number of commas and they will be treated as one. Note the change below:
DECLARE #instr VARCHAR(8000) = 'abc,,,,xxx,,yyy,,z,w,,,,sss,,';
This returns:
value
----------
abc
xxx
yyy
z
w
sss
To understand the performance difference let's do a quick test.
PRINT CHAR(10)+'STRING_SPLIT'+CHAR(10)+REPLICATE('-',90);
GO
DECLARE #st DATETIME = GETDATE(), #x VARCHAR(8000);
SELECT #x = split.[value]
FROM #strings AS s
CROSS APPLY STRING_SPLIT(s.String,',') AS split
WHERE split.[value] > ''
PRINT DATEDIFF(MS,#st,GETDATE());
GO 3
PRINT CHAR(10)+'dbo.MultiStringToTable'+CHAR(10)+REPLICATE('-',90);
GO
DECLARE #st DATETIME = GETDATE(), #x VARCHAR(8000);
SELECT #x = split.id
FROM #strings AS s
CROSS APPLY dbo.MultiStringToTable(s.String) AS split
WHERE split.id > '';
PRINT DATEDIFF(MS,#st,GETDATE());
GO 3
STRING_SPLIT
--------------------------------------------------------------------------------------
Beginning execution loop
140
184
153
Batch execution completed 3 times.
dbo.MultiStringToTable
--------------------------------------------------------------------------------------
Beginning execution loop
14046
14174
14466
Batch execution completed 3 times.
STRING_SPLIT is about One Hundred times faster and with much less code to boot.
wrong parameter name: #InStr - correct
missed BEGIN keyword after WHILE
correct version:
CREATE function MultiStringToTable (#InStr VARCHAR(255))
RETURNS #TempTab TABLE(
id nvarchar(255) not null
)
AS
BEGIN
-- Ensure input ends with comma
SET #InStr = REPLACE(#InStr + ',', ',,', ',');
DECLARE #SP INT;
DECLARE #VALEUR VARCHAR(1000);
WHILE PATINDEX('%,%', #INSTR ) <> 0
BEGIN
SET #SP = PATINDEX('%,%',#INSTR);
SET #VALEUR = LEFT(#INSTR , #SP - 1);
SET #INSTR = STUFF(#INSTR, 1, #SP, '');
INSERT INTO #TempTab(id) VALUES (#VALEUR);
END;
RETURN;
end;

SQL WHILE (String manipulation)

I got a text string consists of 38 chars or so, and i want to search for that string in the database in a specific column. If there is a match, i want the corresponding value from another column as result. If no match is found, i want the string to get cut off by one char from the right hand side, and a new match search performed. This should repeat until either a match if found OR i'm running out of characters
Can anyone please point me in the right direction?
This is the code i made so far, but it's not really doing what i expect it to:
SET NOCOUNT ON
DECLARE #ITEM VARCHAR(38)
DECLARE #CTR INT = 0
DECLARE #RES VARCHAR(40)
SET #ITEM = 'KLS3055P3H01T01A3913 STDP STDP V2 SOMO'
SET #RES = NULL
WHILE #RES IS NULL
BEGIN
SET #RES = (SELECT A.a_nr FROM spekgbp.dbo.art A WHERE A.a_bet LIKE #ITEM)
SET #ITEM = LEFT(#ITEM, LEN(#ITEM)-1)
SET #CTR = #CTR + 1
IF (#CTR =10)
BREAK
END
SELECT #RES as 'RES', #ITEM as 'ITEM'
This is my proposal, if I understand you correctly:
SET NOCOUNT ON
DECLARE #ITEM VARCHAR(38)
DECLARE #CTR INT = 0
DECLARE #RES VARCHAR(40)
SET #ITEM = 'KLS3055P3H01T01A3913 STDP STDP V2 SOMO'
SET #RES = NULL
WHILE (1 = 1)
BEGIN
SET #RES = (SELECT MIN(A.a_nr) FROM spekgbp.dbo.art A WHERE A.a_bet = #ITEM)
IF (#RES IS NOT NULL)
BEGIN
BREAK
END
SET #ITEM = LEFT(#ITEM, LEN(#ITEM)-1)
SET #CTR = #CTR + 1
IF (#CTR = 10)
BEGIN
BREAK
END
END
SELECT #RES as 'RES', #ITEM as 'ITEM'
I added the infinate loop, because when match is found #ITEM is still cut at the end, and in my way loop breaks immediately after #RES is found.

Find word in a string with a character

I have tried so many times but could not find the exact query yet.
The one I made works in few string but doesn't work in another(It is uncertain).
What i want is the word which has '.' in it like "abcde sfjhjk.dkjb sajb njdhf", what i want is "sfjhjk.dkjb" as result . This is just an example.
The query returns all letters in some cases while truncates few digits in other cases. You can check by providing different values.
I tried below :
This doesn't work:
DECLARE #QUERY VARCHAR(MAX)='
renewreque0_.amount AS AMOUNT48_,
renewreque0_.charge_type AS CHARGE3_48_,
renewreque0_.commission_rate AS COMMISSION4_48_
'
SET NOCOUNT ON;
DECLARE #TABLENAME TABLE(TABLE_NAME VARCHAR(MAX),ALIAS VARCHAR(MAX))
DECLARE #COLUMNS_JOIN TABLE(COL VARCHAR(MAX),COLUMN_NAME VARCHAR(MAX),ALIAS VARCHAR(MAX))
DECLARE #NAME VARCHAR(MAX),#ALIAS VARCHAR(MAX),#J_QUERY VARCHAR(MAX),#W_QUERY VARCHAR(MAX)
DECLARE #WHERE_JOIN TABLE(COL VARCHAR(MAX),COLUMN_NAME VARCHAR(MAX),ALIAS VARCHAR(MAX))
WHILE CHARINDEX('.',#QUERY)>1
BEGIN
SET #NAME = REVERSE( SUBSTRING(REVERSE(#QUERY),CHARINDEX('.',REVERSE(#QUERY))+1,CHARINDEX(' ',#QUERY)) )
SET #ALIAS= REVERSE(LEFT(REVERSE(#QUERY),CHARINDEX('.',REVERSE(#QUERY))))
SET #ALIAS=LEFT(#ALIAS,CHARINDEX(' ',#ALIAS))
SET #NAME=LTRIM(RTRIM(#NAME))
SET #ALIAS=LTRIM(RTRIM(#ALIAS))
INSERT INTO #COLUMNS_JOIN SELECT #NAME+#ALIAS,#NAME,REVERSE(LEFT(REVERSE(#ALIAS),LEN(#ALIAS)-1))
SET #QUERY=REPLACE(#QUERY,#NAME+#ALIAS,'')
END
SELECT * FROM #COLUMNS_JOIN
This works:
DECLARE #QUERY VARCHAR(MAX)='
AND t8_.username LIKE ?
AND t4_.branch_id = ?
AND t1_.account_no = ?
AND t0_.remarks = ?
AND t0_.collect_from = ?
'
SET NOCOUNT ON;
DECLARE #TABLENAME TABLE(TABLE_NAME VARCHAR(MAX),ALIAS VARCHAR(MAX))
DECLARE #COLUMNS_JOIN TABLE(COL VARCHAR(MAX),COLUMN_NAME VARCHAR(MAX),ALIAS VARCHAR(MAX))
DECLARE #NAME VARCHAR(MAX),#ALIAS VARCHAR(MAX),#J_QUERY VARCHAR(MAX),#W_QUERY VARCHAR(MAX)
DECLARE #WHERE_JOIN TABLE(COL VARCHAR(MAX),COLUMN_NAME VARCHAR(MAX),ALIAS VARCHAR(MAX))
WHILE CHARINDEX('.',#QUERY)>1
BEGIN
SET #NAME = REVERSE( SUBSTRING(REVERSE(#QUERY),CHARINDEX('.',REVERSE(#QUERY))+1,CHARINDEX(' ',#QUERY)) )
SET #ALIAS= REVERSE(LEFT(REVERSE(#QUERY),CHARINDEX('.',REVERSE(#QUERY))))
SET #ALIAS=LEFT(#ALIAS,CHARINDEX(' ',#ALIAS))
SET #NAME=LTRIM(RTRIM(#NAME))
SET #ALIAS=LTRIM(RTRIM(#ALIAS))
INSERT INTO #COLUMNS_JOIN SELECT #NAME+#ALIAS,#NAME,REVERSE(LEFT(REVERSE(#ALIAS),LEN(#ALIAS)-1))
SET #QUERY=REPLACE(#QUERY,#NAME+#ALIAS,'')
END
SELECT * FROM #COLUMNS_JOIN
Can anybody please help.
I would first use an SplitString function (passing a blank space as delimiter), which returns as rows each word on a string, and then filter it to return just the words having a dot.
SQL Server 2016 already has one https://learn.microsoft.com/en-us/sql/t-sql/functions/string-split-transact-sql and on older SQL Servers you can build your own : Splitting the string in sql server
set #SQLStr varchar(512) = 'abcde sfjhjk.dkjb sajb njdhf';
select value from string_split(#SQLStr, ' ')
where charindex('.', value) > 0
Alright just for fun
declare #str nvarchar(100) = 'abcde sfjhjk.dkjb sajb njdhf',
#pointIndex int
SET #pointIndex = (SELECT CHARINDEX('.',#str) )
SELECT RTRIM(LTRIM(SUBSTRING(#str, #pointIndex - CHARINDEX(' ',REVERSE(LEFT(#str,#pointIndex))) +1,CHARINDEX(' ',REVERSE(LEFT(#str,#pointIndex)))) -- left side
+SUBSTRING(#str,#pointIndex +1, CHARINDEX( ' ', SUBSTRING(#str,#pointIndex,len(#str) - #pointIndex) ) -1 )))
Needless to say i would not recommend this option because it is really hard to maintain. As Marc said your best option here is to split your string for blanks and find the ones with a '.'
Now if you dont have SQLServer 2016 here is a split function for you :
CREATE function [dbo].[Split]
(
#string nvarchar(max),
#delimiter nvarchar(20)
)
returns #table table
(
[Value] nvarchar(max)
)
begin
declare #nextString nvarchar(max)
declare #pos int, #nextPos int
set #nextString = ''
set #string = #string + #delimiter
set #pos = charindex(#delimiter, #string)
set #nextPos = 1
while (#pos <> 0)
begin
set #nextString = substring(#string, 1, #pos - 1)
insert into #table
(
[Value]
)
values
(
#nextString
)
set #string = substring(#string, #pos + len(#delimiter), len(#string))
set #nextPos = #pos
set #pos = charindex(#delimiter, #string)
end
return
end
And use it as such :
SELECT * FROM dbo.Split(REPLACE(#str,' ','/'),'/')
WHERE charindex('.', value) > 0
Note that i replace blanks by another value.

Conversion failed when converting the varchar value ',1,2,3' to data type int

This error results when attempting to use a comma delimited parameter in an IN condition
I'm passing a varchar parameter to a stored procedure that looks like this
,1,2,3
And I want to find out if it contains 1 (it doesn't always contain 1)
What's the easiest way to do that in TSQL ?
declare #Nums varchar(max)=',1,2,3'
if 1 in (#Nums) -- conversion error
BEGIN
select * from TestTable
END
You will need to use LIKE to see if the string contains the character 1. Note this will also match 12 or any string with the character '1' in it.
declare #Nums varchar(max)=',1,2,3'
if #Nums LIKE '%1%'
BEGIN
select * from TestTable
END
If you need to match the full number:
CREATE FUNCTION [dbo].[Split_String]
(
#ItemList NVARCHAR(4000),
#delimiter CHAR(1)
)
RETURNS #IDTable TABLE (Item VARCHAR(50))
AS
BEGIN
DECLARE #tempItemList NVARCHAR(4000)
SET #tempItemList = #ItemList
DECLARE #i INT
DECLARE #Item NVARCHAR(4000)
SET #tempItemList = REPLACE (#tempItemList, ' ', '')
SET #i = CHARINDEX(#delimiter, #tempItemList)
WHILE (LEN(#tempItemList) > 0)
BEGIN
IF #i = 0
SET #Item = #tempItemList
ELSE
SET #Item = LEFT(#tempItemList, #i - 1)
INSERT INTO #IDTable(Item) VALUES(#Item)
IF #i = 0
SET #tempItemList = ''
ELSE
SET #tempItemList = RIGHT(#tempItemList, LEN(#tempItemList) - #i)
SET #i = CHARINDEX(#delimiter, #tempItemList)
END
RETURN
END
DECLARE #Nums VARCHAR(MAX) = ',1,2,3'
DECLARE #NumberTable TABLE (item INT)
INSERT INTO #NumberTable
SELECT TRY_CAST(Item AS INT)
FROM dbo.Split_String(#Nums, ',')
IF (SELECT 1 FROM #NumberTable WHERE item = 1) = 1
BEGIN
select * from TestTable
END
You can use CHARINDEX.
declare #Nums varchar(max)=',1,2,3'
IF CHARINDEX(',1,', #Nums+',') > 0
BEGIN
select * from TestTable
END

Transform text in SQL Server

I am trying to create a dynamic query in SQL Server.
Input: #value= abc,def,en,
Output: MAX(abc) as abc, MAX(def) as def, MAX(en) as en
My efforts so far took me no where.
With CONVERT() and REPLACE() I achieved a bit but finding it difficult. Need help!
Try this:
declare #value varchar(50) = 'abc,def,en'
declare #result varchar(100) = ''
select #result = replace(#value,'abc', 'MAX(''abc'') as abc')
select #result = replace(#result,'def', 'MAX(''def'') as def')
select #result = replace(#result,'en', 'MAX(''en'') as en')
select #result
You can also do the replacements in one line by nesting the expressions.
EDIT: If you have variable values in #value, you can take the below approach:
Use a splitter function to get the individual values in the string as a list. You can take a look at this article for implementations.
Insert this list to a temp table.
Update the temp table as shown above.
Concatenate the values into a single string using STUFF like so:
select stuff((select ',' + val from #temp for xml path('')),1,1,'')
Try this:
DECLARE #Value VARCHAR(200) = 'abc,def,en'
DECLARE #Template VARCHAR(100) = 'MAX(''##'') as ##'
DECLARE #Result VARCHAR(1000) = ''
DECLARE #Data VARCHAR(100) = ''
WHILE LEN(#Value) > 0
BEGIN
SET #Data = REPLACE(LEFT(#Value, ISNULL(NULLIF(CHARINDEX(',', #Value),0), LEN(#Value))),',','')
SET #Result = #Result + REPLACE(#Template, '##', #Data)
IF CHARINDEX(',', #Value) > 0
BEGIN
SET #Result = #Result + ','
SET #Value = REPLACE(#Value,#Data + ',','')
END
ELSE
SET #Value = REPLACE(#Value,#Data,'')
END
SELECT #Result
Have a look at SQL User Defined Function to Parse a Delimited String
So you can do like
Declare #Value varchar(200) = 'abc,def,en'
Declare #Item varchar(20) = null
declare #Str varchar(1000)=''
WHILE LEN(#Value) > 0
BEGIN
IF PATINDEX('%,%',#Value) > 0
BEGIN
SET #Item = SUBSTRING(#Value, 0, PATINDEX('%,%',#Value))
-- SELECT #Item
IF(LEN(#Str)>0)
SET #Str = #Str + ', SELECT MAX('+#Item+') as ' +#Item
ELSE
SET#Str = #Str + ' SELECT MAX('+#Item+') as ' +#Item
SET #Value = SUBSTRING(#Value, LEN(#Item + ',') + 1, LEN(#Value))
END
ELSE
BEGIN
SET #Item = #Value
SET #Value = NULL
SET #Str = #Str + 'SELECT MAX('+#Item+') as ' + #Item
END
END
select #Str
See the fiddle sample here

Resources