Find a specific substring using Transact-SQL - sql

I need to pull a specific substring from a string of the form:
foo=abc;bar=def;baz=ghi
For example, how would I get the value of "bar" from that string?

You can use charindex and substring. For example, to search for the value of "baz":
declare #str varchar(128)
set #str = 'foo=abc;bar=def;baz=ghi'
-- Make sure #str starts and ends with a ;
set #str = ';' + #str + ';'
select substring(#str,
charindex(';baz=',#str) + len(';baz='),
charindex('=',#str,charindex(';baz=',#str)) - charindex(';baz=',#str) - 1)
Or for the value of "foo" at the start of the string:
select substring(#str,
charindex(';foo=',#str) + len(';foo='),
charindex('=',#str,charindex(';foo=',#str)) - charindex(';foo=',#str) - 1)
Here's a UDF to accomplish this (more readable version inspired by BlackTigerX's answer):
create function dbo.FindValueInString(
#search varchar(256),
#name varchar(30))
returns varchar(30)
as
begin
declare #name_start int
declare #name_length int
declare #value_start int
declare #value_end int
set #search = ';' + #search
set #name_start = charindex(';' + #name + '=',#search)
if #name_start = 0
return NULL
set #name_length = len(';' + #name + '=')
set #value_start = #name_start + #name_length
set #value_end = charindex(';', #search, #value_start)
return substring(#search, #value_start, #value_end - #value_start)
end
As you can see, this isn't easy in Sql Server :) Better do this in the client language, or normalize your database so the substrings go in their own columns.

I have a generalized solution that works for this problem:
CREATE FUNCTION [dbo].[fn_StringBetween]
(
#BaseString varchar(max),
#StringDelim1 varchar(max),
#StringDelim2 varchar(max)
)
RETURNS varchar(max)
AS
BEGIN
DECLARE #at1 int
DECLARE #at2 int
DECLARE #rtrn varchar(max)
SET #at1 = CHARINDEX(#StringDelim1, #BaseString)
IF #at1 > 0
BEGIN
SET #rtrn = SUBSTRING(#BaseString, #at1
+ LEN(#StringDelim1), LEN(#BaseString) - #at1)
SET #at2 = CHARINDEX(#StringDelim2, #rtrn)
IF #at2 > 0
SET #rtrn = LEFT(#rtrn, #at2 - 1)
END
RETURN #rtrn
END
so if you run (just wrap your original string to be searched with ';' at beginning and end):
PRINT dbo.fn_StringBetween(';foo=abc;bar=def;baz=ghi;', ';bar=', ';')
you will get 'def' returned.

look into the PATINDEX function. It has wildcard matching which should help you..

you can use this function
alter function FindValue(#txt varchar(200), #find varchar(200))
returns varchar(200)
as
begin
declare
#firstPos int,
#lastPos int
select #firstPos = charindex(#find, #txt), #lastPos = charindex(';', #txt, #firstPos+5)
select #lastPos = len(#txt)+1 where #lastPos = 0
return substring(#txt, #firstPos+len(#find)+1, #lastPos-#firstPos-len(#find)-1)
end
select dbo.FindValue('foo=abc;bar=def;baz=ghi', 'bar')
update: was not using the length of #find

this is assuming that the string will have the same string format just substitute the column name for the 'foo=abc;bar=def;baz=ghi'
select substring('foo=abc;bar=def;baz=ghi',patindex('%bar=%','foo=abc;bar=def;baz=ghi')+4, len('foo=abc;bar=def;baz=ghi')-patindex('%;baz=%','foo=abc;bar=def;baz=ghi')-4)

This can achieve in simple way
DECLARE #str VARCHAR(30)
DECLARE #start INT
SET #str='foo=abc;bar=def;baz=ghi'
SET #start=CHARINDEX('bar',#str)
PRINT SUBSTRING(#str,#start,3)

Related

Replace substring between two delimiters or until the end of string

In a procedure in SQL Server 2008 I need to replace a substring between 2 identifiers. I do not know the complete strings to be replaced, or if the second identifier exists.
If the terminator identifier is not present, I would need the end of the string to be considered one. Also, the identifiers could be the same.
DECLARE #startIdenfier VARCHAR(10) = 'the'
DECLARE #endIdenfier VARCHAR(10) = 'the'
DECLARE #newString VARCHAR(20) = 'new string that'
Sample input / output:
'This is the old string that the process needs to be applied on.' ->
'This is the new string that the process needs to be applied on.'
'This is the old string' ->
'This is the new string that'
SET #endIdenfier = 'I'
'This is the old string that I don't like' ->
'This is the new string that I don't like''
It is a generic replace and I havn't been able to find the proper way to do it, since the REPLACE function does not accept indexes.
EDIT: This community is awesome. I am sorry I cannot select multiple accepted solutions, but I thank you all for your help. I'll try all solutions already posted (besides the already accepted one which I tested) and up-vote individually.
--Find the start index plus the length of the string found (plus one for the space)
SET #startIdx = CHARINDEX(#startIdentifier, #initialString, 1) + LEN(#startIdentifier) + 1
--Find the next occurrence of the end identifier (minus one for the space)
SET #endIdx = CHARINDEX(#endIdentifier, #initialString, #startIdx) - 1;
--end not found?
IF #endIdx = -1 SET #endIdx = LEN(#initialString) + 1;
--Use the STUFF function to remove the old chars from endindex-startindex, and insert the new string at the startindex
SET #results = STUFF(#initialString, #startIdx, #endIdx - #startIdx, #newString)
In full:
DECLARE #startIdenfier Varchar(10)
SET #startIdenfier = 'the'
DECLARE #endIdenfier Varchar(10)
SET #endIdenfier = 'the'
DECLARE #newString Varchar(100)
SET #newString = 'new string that'
DECLARE #initialString VARCHAR(256) = 'this is the old string that the process needs to be applied on';
DECLARE #startIdx INT;
SET #startIdx = CHARINDEX(#startIdenfier, #initialString, 1) + LEN(#startIdenfier) + 1;
DECLARE #endIdx INT;
SET #endIdx= CHARINDEX(#endIdenfier, #initialString, #startIdx) - 1;
IF #endIdx = -1 SET #endIdx = LEN(#initialString) + 1;
DECLARE #results VARCHAR(256);
SET #results = STUFF(#initialString, #startIdx, #endIdx - #startIdx, #newString);
SELECT #results
You could do something like this:
/*Declare necessary variables*/
DECLARE #startIndex INT
DECLARE #endIndex INT
DECLARE #startReplace INT
DECLARE #lengthReplace INT
DECLARE #replaceString VARCHAR(500)
/*Get the index of the start/end idenfier*/
SELECT #startIndex = CHARINDEX ( #startIdenfier , #originalString)
SELECT #endIndex = CHARINDEX ( #startIdenfier , #originalString, #startIndex+1)
/*In case the end idenfier doesn't exist*/
IF #endIndex = 0
SET #endIndex = LEN(#originalString) + 1
SET #startReplace = #startIndex + len(#startIdenfier)
SET #lengthReplace = #endIndex - #startReplace
SELECT STUFF(#originalString, #startReplace, #lengthReplace, #newString)
I think you will need to incorporate the PATINDEX function and create the pattern by using your start and end identifiers. That will satisfy the condition where both start and end identifiers are present...
DECLARE #OldString nvarchar(max)
DECLARE #NewString nvarchar(max)
DECLARE #StartLocation bigint
DECLARE #Pattern nvarchar(200) = '%' + #StartIdentifier + ' % ' + #EndIdentifer + '%'
SELECT #StartLocation = PATINDEX(#Pattern, 'old complete string')
If the pattern is located, then you can get the string to be replaced by substringing the 'old complete string', starting at position (#StartLocation + Length of #StartIdentifier + 1). To determine the length for SUBSTRING, you need to locate the position of #EndIdentifier, using CHARINDEX of the old complete string beginning at ( #StartLocation + Length of #StartIdentifier + 1). Subtract ( #StartLocation + Length of StartIdentifier + 1) from result of CHARINDEX.
SELECT #OldString = SUBSTRING('complete old string', #StartLocation + LEN(#StartIdentifier) + 1, CHARINDEX(' ' + #EndIdentifier, 'old complete string', #StartLocation + LEN(#StartIdentifier) + 1) - (#StartLocation + LEN(#StartIdentifier) + 1)))
You can at this point do a straight forward REPLACE to get the new string.
SELECT #NewCompleteString = REPLACE('old complete string', #OldString, #NewString)
"If there is no 'terminator' identifier, I would need the end of the
string to be considered one."
If the initial pattern was not located, we fall back to search for the #StartIdentifier only. For this you can reset the pattern to contain the #StartIdentifier only...
SELECT #Pattern = '%' + #StartIdentifier + ' %'
SELECT #StartLocation = PATINDEX(#Pattern, 'old complete string')
If the pattern is located then you can get the old string to replace by SUBSTRING starting at ( #StartLocation + Length of #StartIdentifier + 1 ), with a length of 'old complete string' length - ( #StartLocation + Length of #StartIdentifier + 1 )...
SELECT #OldString = SUBSTRING('old complete string', #StartLocation + LEN(#StartIdentifier) + 1, LEN('old complete string') - (#StartLocation + LEN(#StartIdentifier) + 1))
You can then REPLACE...
SELECT #NewCompleteString = REPLACE('old complete string', #OldString, #NewString)
Something like this...
DECLARE #initialString VARCHAR(32) = '1234567890123456789'
DECLARE #startIdentifier VARCHAR(32) = '34'
DECLARE #endIdentifier VARCHAR(32) = '34'
DECLARE #newString VARCHAR(32) = 'ABC'
DECLARE #headChars INT = CHARINDEX(#startIdentifier, #initialString, 1)
IF #headChars > 0
SET #headChars = #headChars + LEN(#startIdentifier) - 1
DECLARE #bodyChars INT = CHARINDEX(#endIdentifier, #initialString, #headChars + 1)
IF #bodyChars > 0
SET #bodyChars = LEN(#initialString) - #bodyChars + 1
SELECT
LEFT(#initialString, #headChars)
+ #newString
+ RIGHT(#initialString, #bodyChars)
https://dbfiddle.uk/?rdbms=sqlserver_2017&fiddle=b8a179d0e63840dfa60905d9951e4b22
For example...
'1234567890123456789'
'34' => Start # 1 => Found # 3 => keep chars 1->4
'34' => Start # 5 => Found # 13 => keep chars 13->end
Just use STUFF and CHARINDEX. Figure out:
the position at which replacement begins (position of the + length of the)
the position at which replacement ends (position of the starting from see above)
And subtract the positions to calculate the number of characters to replace.
DECLARE #string VARCHAR(100) = 'This is the old string that the process needs to be applied on.'
DECLARE #replace VARCHAR(100) = 'NEW STRING THAT '
DECLARE #delim1 VARCHAR(100) = 'the '
DECLARE #delim2 VARCHAR(100) = 'the '
DECLARE #pos1 INT = CHARINDEX(#delim1, #string) + DATALENGTH(#delim1)
DECLARE #pos2 INT = ISNULL(NULLIF(CHARINDEX(#delim2, #string, #pos1), 0), DATALENGTH(#string) + 1)
SELECT STUFF(#string, #pos1, #pos2 - #pos1, #replace)
-- "This is the NEW STRING THAT the process needs to be applied on."
SET #delim2 = 'xxx'
SET #pos1 = CHARINDEX(#delim1, #string) + DATALENGTH(#delim1)
SET #pos2 = ISNULL(NULLIF(CHARINDEX(#delim2, #string, #pos1), 0), DATALENGTH(#string) + 1)
SELECT STUFF(#string, #pos1, #pos2 - #pos1, #replace)
-- "This is the NEW STRING THAT "
Note: spaces should be a part of search delimiters instead of the logic. the should not match them and threfore.

How to parse an array in sql server

I created a stored procedure that looks like this.
CREATE PROCEDURE [EXP_RfPickAfter] (
#SESSIONVALUE xml,
#WorkDSArray nvarchar(max),
#UserSignonDS nvarchar(max),
#Direction nvarchar(max),
#ImmediateCount nvarchar(max),
#CCWorkUnit nvarchar(max),
#PartialPick nvarchar(max),
#RETURNVALUE nvarchar(max) output
)
AS
SET NOCOUNT ON;
#workDSArray has this long string in it
924WORK0924841SEQUENCE8410841842EQUIPMENT_LOC842842843PARENT_LOGISTICS_
UNIT843843844REFERENCE_TYPE844Order844845INVENTORY_AT_
PD845845846FROMVER846None846847INTERNAL_NUM8476851842847848START_
DATE_TIME848848849INCHKDIG849849850TOTAL_VOLUME8500850851
TO_LOC851SHIP-1851852INTERNAL_NUM_TYPE852Shipment852853
WEIGHT_UM853LB853854COMPANY854SHOS854855QUANTITY_UM855CS855856OUTGOING_
PD_LOC856856857WORK_TYPE857LPNPick857858END_DATE_TIME858858859
ACTUALFROMWHS859L455859860LOT860860861WORK_ZONE1861861862
TOCONTAINERID8621862863INVER863863864TRACK_CONTAINERS864N864865
TO_LOC_INV_ATTRIBUTES_ID865865866CYCLE_COUNT866866867
LAUNCH_NUM86716949391867868ACTUALTOLOC868-jisavm3868869
FROM_CHECK_DIG869869870FROM_WHS870L455870871
WORK_GROUP871Picking871872INTERNAL_LINE_NUM187232612518872873
VOLUME_UM873873874ACTUALFROMLOC874NF-1-F-28-1874875
INTERNAL_REQ_NUM87520774185875876TO_WHS876L455876877
INTERNAL_LINE_NUM87732612518877878TREE_UNIT87826385537878879
INWRKZONE879879880PUTLOC880SHIP-1880881CONTAINER_ID88116489660881882
INTERNAL_CONTAINER_NUM88226385537882883FROMTRKCONT883Y883884
PARENT_CONTAINER_NUM8840884885CONVERTED_QTY_UM885CS885886
ACTUALTOWHS886L455886887OUTWRKZONE887887888
VERIFICATION_METH888None888889USER_DEF4889 L455-RS 2889890
REFERENCE_ID890XKJNNLJN890891LOGISTICS_UNIT89116489660891892
MESSAGE_ID892892893PICKLOC893NF-1-F-28-1893894
CURRENTLOC894F894895TREE_UNIT_ID89516489660895897
TOCONTAINERID089716489660897898TOTAL_WEIGHT8981898899
TOTAL_VALUE8990899900TO_CHECK_DIG900900901OUTCHECKDIG901901902
TO_QTY9020902903INTRKCONT903903904FROM_LOC_INV_ATTRIBUTES_ID904904905
INTERNAL_INSTRUCTION_NUM90520699485905906ITEM_DESC906MSF21D4MDE -
Refrigerator906907ITEM907SHOS-STOCK907908
COMPLETEDBYUSER908jisavm3908909
TRANSPORT_CONT_ID90916489660909910OUTTRKCONT910910911ACCOUNT911
Store #9449911912INCOMING_PD_LOC912912913INVENTORY_TRACKING913Y913914
LOCATION_CLASS914Shipping Dock914915FROM_QTY9151915916OUTVERMETH916916917
CONVERTED_QTY9171917918QUANTITY9181918919
PARENT_INSTR91920699484919920
FROM_LOC920NF-1-F-28-1920921WORK_ZONE921W-
Returns921922WORK_UNIT92216489660922923QTY
CONFIRMED9231923924925WORK9251925
I am trying to parse containerID and its value from this string and use it in a select statement in my stored procedure, but I am unsure how to parse only the containerID.
Any help would be appreciated
This is what I did to get the right ID I had to trigger off of something else. This is not ideal because I don't know if the string will change. If anybody knows a better way please post and thank you #ymuribbi you helped me out a ton. I edited this to show my full solution just in case someone else runs into this issue.
DECLARE #WorkDSArray nvarchar(max);
SET #WorkDSArray= '924WORK0924841SEQUENCE8410841842EQUIPMENT_LOC842842843PARENT_LOGISTICS_UNIT843843844REFERENCE_TYPE844Order844845INVENTORY_AT_PD845845846FROMVER846None846847INTERNAL_NUM8476851842847848START_DATE_TIME848848849INCHKDIG849849850TOTAL_VOLUME8500850851TO_LOC851SHIP-1851852INTERNAL_NUM_TYPE852Shipment852853WEIGHT_UM853LB853854COMPANY854SHOS854855QUANTITY_UM855CS855856OUTGOING_PD_LOC856856857WORK_TYPE857LPN Pick857858END_DATE_TIME858858859ACTUALFROMWHS859L455859860LOT860860861WORK_ZONE1861861862TOCONTAINERID8621862863INVER863863864TRACK_CONTAINERS864N864865TO_LOC_INV_ATTRIBUTES_ID865865866CYCLE_COUNT866866867LAUNCH_NUM86716949391867868ACTUALTOLOC868-jisavm3868869FROM_CHECK_DIG869869870FROM_WHS870L455870871WORK_GROUP871Picking871872INTERNAL_LINE_NUM187232612518872873VOLUME_UM873873874ACTUALFROMLOC874NF-1-F-28-1874875INTERNAL_REQ_NUM87520774185875876TO_WHS876L455876877INTERNAL_LINE_NUM87732612518877878TREE_UNIT87826385537878879INWRKZONE879879880PUTLOC880SHIP-1880881CONTAINER_ID88116489660881882INTERNAL_CONTAINER_NUM88226385537882883FROMTRKCONT883Y883884PARENT_CONTAINER_NUM8840884885CONVERTED_QTY_UM885CS885886ACTUALTOWHS886L455886887OUTWRKZONE887887888VERIFICATION_METH888None888889USER_DEF4889 L455-RS 2889890REFERENCE_ID890XKJNNLJN890891LOGISTICS_UNIT89116489660891892MESSAGE_ID892892893PICKLOC893NF-1-F-28-1893894CURRENTLOC894F894895TREE_UNIT_ID89516489660895897TOCONTAINERID089716489660897898TOTAL_WEIGHT8981898899TOTAL_VALUE8990899900TO_CHECK_DIG900900901OUTCHECKDIG901901902TO_QTY9020902903INTRKCONT903903904FROM_LOC_INV_ATTRIBUTES_ID904904905INTERNAL_INSTRUCTION_NUM90520699485905906ITEM_DESC906MSF21D4MDE - Refrigerator906907ITEM907SHOS-STOCK907908COMPLETEDBYUSER908jisavm3908909TRANSPORT_CONT_ID90916489660909910OUTTRKCONT910910911ACCOUNT911Store #9449911912INCOMING_PD_LOC912912913INVENTORY_TRACKING913Y913914LOCATION_CLASS914Shipping Dock914915FROM_QTY9151915916OUTVERMETH916916917CONVERTED_QTY9171917918QUANTITY9181918919PARENT_INSTR91920699484919920FROM_LOC920NF-1-F-28-1920921WORK_ZONE921W-Returns921922WORK_UNIT92216489660922923QTYCONFIRMED9231923924925WORK9251925'
DECLARE #ContainerID integer;
SET #ContainerID = CHARINDEX('TREE_UNIT_ID', #WorkDSArray);
DECLARE #ID nvarchar(max);
SET #ID = SUBSTRING(#WorkDSArray, #ContainerID,300)
SELECT #ID;
DECLARE #ActualContainerID nvarchar(max);
SET #ActualContainerID = SUBSTRING(#ID, 54, 9)
SET #ActualContainerID = REPLACE(#ActualContainerID, CHAR(31), '')
DECLARE #User integer
DECLARE #UserID nvarchar(max)
SET #User = CHARINDEX('COMPLETEDBYUSER', #WorkDSArray);
SET #UserID = SUBSTRING(#WorkDSArray, #User,27)
DECLARE #ActualUserID nvarchar(max);
SET #ActualUserID = SUBSTRING(#UserID, 20, 8)
SET #ActualUserID = REPLACE(#ActualUserID, CHAR(31), '')
DECLARE #Shipment nvarchar(max)
SET #Shipment = (SELECT CASE WHEN SH.COMPANY = 'SHOS' THEN '' ELSE SH.SHIPMENT_ID + '|' +
SH."ROUTE" + '|' +
SH."STOP" + '|' +
SH.COMPANY + '|' +
LEFT(SH.CUSTOMER_NAME,25) + '|' +
LEFT(SH.SHIP_TO_ADDRESS1,25) + '|' +
CASE WHEN SH.SHIP_TO_ADDRESS2 <> '' THEN SH.SHIP_TO_ADDRESS2 + '|'
ELSE '' END +
LEFT(SH.SHIP_TO_CITY,25) + '|' +
LEFT(SH.SHIP_TO_STATE,25) + '|' +
LEFT(SH.SHIP_TO_POSTAL_CODE,25) END
FROM SHIPMENT_HEADER SH
JOIN SHIPPING_CONTAINER SC
ON SC.INTERNAL_SHIPMENT_NUM = SH.INTERNAL_SHIPMENT_NUM
WHERE SC.CONTAINER_ID = #ActualContainerID)
DECLARE #ShipmentID nvarchar(max)
SET #ShipmentID = SUBSTRING(#Shipment,0,9)
--select top 1 device_name from dbo.DOCUMENT_ROUTING where document_type = 'HJBT_REC' and user_name = #user
INSERT INTO [jbh].[PRT_REQ_WRK]
([REQ_REF_TYP], [REQ_REF_I], [PRT_DVC_NM], [REQ_TMPL_NM], [REQ_VAL], [PRT_STT], [PRT_PRS_TYP], [PRT_Q], [CRT_S], [CRT_UID], [CRT_PGM_C], [LST_UPD_S], [LST_UPD_UID], [LST_UPD_PGM_C])
VALUES (
#ShipmentID, --[REQ_REF_TYP]
'123abc', --[REQ_REF_I]
'LB01885', --[PRT_DVC_NM]
'HJBT_Shipping_Label.lbl', --[REQ_TMPL_NM]
#Shipment, --[REQ_VAL]
0, --[PRT_STT]
'LABEL', --[PRT_PRS_TYP]
1, --[PRT_Q]
CURRENT_TIMESTAMP, --[CRT_S]
#ActualUserID, --[CRT_UID]
'WMSPrintService', --[CRT_PGM_C]
CURRENT_TIMESTAMP, --[LST_UPD_S]
'JISAVM3', --[LST_UPD_UID]
'WMSPrintService') --[LST_UPD_PGM_C]
As #hogan stated in his comment, you can use string operators for extraction with some while and if-else statements
-- I am editing my answer.
To retrieve the container ID you use a store procedure like this:
create proc getid (#string varchar(max)) as
declare #containerIdIndex int = (select charindex('CONTAINER_ID',#string))
declare #internalContainerIndex int = (select(Charindex('INTERNAL_CONTAINER', #string)))
declare #range int = #internalContainerindex-#containerIdindex+12
declare #start int = #containerIdIndex+12 --12 is to pass the 'Container_ID'
declare #containerId varchar(max)
set #containerId = substring(#string,#start,#range)
print #containerId

Converting String List into Int List in SQL

I have a nvarchar(MAX) in my stored procedure which contains the list of int values, I did it like this as it is not possible to pass int list to my stored procedure,
but, now I am getting problem as my datatype is int and I want to compare the list of string.
Is there a way around by which I can do the same?
---myquerry----where status in (#statuslist)
but the statuslist contains now string values not int, so how to convert them into INT?
UPDate:
USE [Database]
GO
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
ALTER PROCEDURE [dbo].[SP]
(
#FromDate datetime = 0,
#ToDate datetime = 0,
#ID int=0,
#List nvarchar(MAX) //This is the List which has string ids//
)
AS
SET FMTONLY OFF;
DECLARE #sql nvarchar(MAX),
#paramlist nvarchar(MAX)
SET #sql = 'SELECT ------ and Code in(#xList)
and -------------'
SELECT #paramlist = '#xFromDate datetime,#xToDate datetime,#xId int,#xList nvarchar(MAX)'
EXEC sp_executesql #sql, #paramlist,
#xFromDate = #FromDate ,#xToDate=#ToDate,#xId=#ID,#xList=#List
PRINT #sql
So when I implement that function that splits then I am not able to specify the charcter or delimiter as it is not accepting it as (#List,',').
or (','+#List+',').
It is possible to send an int list to your stored procedure using XML parameters. This way you don't have to tackle this problem anymore and it is a better and more clean solution.
have a look at this question:
Passing an array of parameters to a stored procedure
or check this code project:
http://www.codeproject.com/Articles/20847/Passing-Arrays-in-SQL-Parameters-using-XML-Data-Ty
However if you insist on doing it your way you could use this function:
CREATE FUNCTION [dbo].[fnStringList2Table]
(
#List varchar(MAX)
)
RETURNS
#ParsedList table
(
item int
)
AS
BEGIN
DECLARE #item varchar(800), #Pos int
SET #List = LTRIM(RTRIM(#List))+ ','
SET #Pos = CHARINDEX(',', #List, 1)
WHILE #Pos > 0
BEGIN
SET #item = LTRIM(RTRIM(LEFT(#List, #Pos - 1)))
IF #item <> ''
BEGIN
INSERT INTO #ParsedList (item)
VALUES (CAST(#item AS int))
END
SET #List = RIGHT(#List, LEN(#List) - #Pos)
SET #Pos = CHARINDEX(',', #List, 1)
END
RETURN
END
Call it like this:
SELECT *
FROM Table
WHERE status IN (SELECT * from fnStringList2Table(#statuslist))
You can work with string list too. I always do.
declare #statuslist nvarchar(max)
set #statuslist = '1, 2, 3, 4'
declare #sql nvarchar(max)
set #sql = 'select * from table where Status in (' + #statuslist + ')'
Execute(#sql)
You can do this by using sql function which will return you an integer array..
It would be great if you pass #Delimiter separated string to your stored procedure which could be processed properly afterwards.
Write one function to split the data as following
CREATE FUNCTION [dbo].[SplitValues] (#StringArray NVARCHAR(MAX), #Delimiter NVARCHAR(10))
RETURNS #ResultedValues table
(
ResultValue INT
)
AS
BEGIN
DECLARE #Tokens TABLE(Token nvarchar)
DECLARE #String nvarchar
WHILE (CHARINDEX(#Delimiter,#StringArray)>0)
BEGIN
INSERT INTO #Tokens (Token) VALUES (LTRIM(RTRIM(SUBSTRING(#StringArray,1,CHARINDEX(#Delimiter,#StringArray)-1))))
SET #String = SUBSTRING(#StringArray,
CHARINDEX(#Delimiter,#StringArray)+LEN(#Delimiter),LEN(#StringArray))
END
INSERT INTO #ResultedValues (ResultValue ) VALUES ( CAST(LTRIM(RTRIM(#String)) AS INT))
RETURN
END
And then use it like following, i am using (,) as #Delimiter here
SELECT ResultValue [YourSchema].[SplitValues](#statuslist,',')
Actually, you can send the list of int values to your procedure by creating a User Defined Table Type. However, this implies more work in order to populate the table parameter.
In your case, you can use the sp_executesql stored procedure to achieve what you want like this:
declare #statement nvarchar(4000) = '----your query---- where status in ('
+ #statusList +')'
sp_executesql #statement
here is an example of how to do it and the Link for more informations
ALTER FUNCTION iter_intlist_to_tbl (#list nvarchar(MAX))
RETURNS #tbl TABLE (listpos int IDENTITY(1, 1) NOT NULL,
number int NOT NULL) AS
BEGIN
DECLARE #startpos int,
#endpos int,
#textpos int,
#chunklen smallint,
#str nvarchar(4000),
#tmpstr nvarchar(4000),
#leftover nvarchar(4000)
SET #textpos = 1
SET #leftover = ''
WHILE #textpos <= datalength(#list) / 2
BEGIN
SET #chunklen = 4000 - datalength(#leftover) / 2
SET #tmpstr = ltrim(#leftover + substring(#list, #textpos, #chunklen))
SET #textpos = #textpos + #chunklen
SET #startpos = 0
SET #endpos = charindex(' ' COLLATE Slovenian_BIN2, #tmpstr)
WHILE #endpos > 0
BEGIN
SET #str = substring(#tmpstr, #startpos + 1, #endpos - #startpos - 1)
IF #str <> ''
INSERT #tbl (number) VALUES(convert(int, #str))
SET #startpos = #endpos
SET #endpos = charindex(' ' COLLATE Slovenian_BIN2, #tmpstr, #startpos + 1)
END
SET #leftover = right(#tmpstr, datalength(#tmpstr) / 2 - #startpos)
END
IF ltrim(rtrim(#leftover)) <> ''
INSERT #tbl (number) VALUES(convert(int, #leftover))
RETURN
END
-- ############################ Example ############################
--CREATE PROCEDURE get_product_names_iter #ids varchar(50) AS
--SELECT P.ProductName, P.ProductID
--FROM Northwind..Products P
--JOIN iter_intlist_to_tbl(#ids) i ON P.ProductID = i.number
--go
--EXEC get_product_names_iter '9 12 27 37'
-- ############################ WICHTIG ############################
This works for me on an Informix DataBase:
DROP FUNCTION rrhh:fnc_StringList_To_Table;
CREATE FUNCTION rrhh:fnc_StringList_To_Table (pStringList varchar(250))
RETURNING INT as NUMERO;
/* A esta Funcion le podes pasar una cadena CSV con una lista de numeros
* Ejem: EXECUTE FUNCTION fnc_StringList_To_Table('1,2,3,4');
* y te devolvera una Tabla con dichos numeros separados uno x fila
* Autor: Jhollman Chacon #Cutcsa - 2019 */
DEFINE _STRING VARCHAR(255);
DEFINE _LEN INT;
DEFINE _POS INT;
DEFINE _START INT;
DEFINE _CHAR VARCHAR(1);
DEFINE _VAL INT;
LET _STRING = REPLACE(pStringList, ' ', '');
LET _START = 0;
LET _POS = 0;
LET _LEN = LENGTH(_STRING);
FOR _POS = _START TO _LEN
LET _CHAR = SUBSTRING(pStringList FROM _POS FOR 1);
IF _CHAR <> ',' THEN
LET _VAL = _CHAR::INT;
ELSE
LET _VAL = NULL;
END IF;
IF _VAL IS NOT NULL THEN
RETURN _VAL WITH RESUME;
END IF;
END FOR;
END FUNCTION;
EXECUTE FUNCTION fnc_StringList_To_Table('1,2,3,4');
SELECT * FROM TABLE (fnc_StringList_To_Table('1,2,3,4'));

Looking for multiples substrings within a SQL string

I have several occurrences of differences strings in the columns, like this example
'dsasdasdsd'+'ewewewew'+'45454545'+(avg('uuuuuuu'))
I need to split this string into several columns with the substrings that are between
aphostropes
like this:
Column 1 = dsasdasdsd
Column 2 = ewewewew
Column 3 = 45454545
Column 4 = uuuuuuu
The numbers of apperances are random, thefore the length of the original column is also not fixed (from 50 char to > 1000)
DECLARE #InStr VarChar(1000) = '''dsasdasdsd''+''ewewewew''+''45454545''+(avg(''uuuuuuu''))'''
DECLARE #intStart INT = 0
DECLARE #intEnd INT = 1
DECLARE #ColNo INT = 1
DECLARE #MyString VARCHAR(2000)
DECLARE #SelectString VARCHAR(8000) = 'SELECT '
WHILE(#intStart < LEN(#InStr) )
BEGIN
SELECT #intStart = CHARINDEX(CHAR(39), #InStr, 0) + 1
SELECT #intEnd = CHARINDEX(CHAR(39), #InStr, #intStart)
SELECT #SelectString = #SelectString + CHAR(39) + SUBSTRING(#InStr, #intStart, #intEnd - #intStart) + CHAR(39) + ' As [Column ' + CAST(#ColNo As Varchar) + '],'
SELECT #InStr = SUBSTRING(#InStr, #intEnd + 1, LEN(#InStr)-#intEnd )
SET #ColNo = #ColNo +1
END
SELECT #SelectString = LEFT(#SelectString, Len(#SelectString) -1)
EXEC (#SelectString)
I have been playing with this and this does run but unfortunately I don't have time right now to carry on with it but maybe you can improve on this?
HTH
You can try this:
create table tSqlStrings (sText nvarchar(1000))
insert tSqlStrings values('''dsasdasdsd''+''ewewewew''+''45454545''+(avg(''uuuuuuu''))')
create table tResults (
sColumn1 nvarchar(1000)
,sColumn2 nvarchar(1000)
,sColumn3 nvarchar(1000)
,sColumn4 nvarchar(1000)
)
and
DELETE tResults
DECLARE #sText nvarchar(1000) = (
SELECT
sText
FROM
tSqlStrings
)
DECLARE #lBegin int = CHARINDEX('''',#sText)
DECLARE #lEnd int = charindex('''',
substring(#sText,
CHARINDEX('''',#sText)+1,
len(#sText)))
DECLARE #sText0 nvarchar(1000)
DECLARE #sColumn1 nvarchar(1000)
DECLARE #sColumn2 nvarchar(1000)
DECLARE #sColumn3 nvarchar(1000)
DECLARE #sColumn4 nvarchar(1000)
DECLARE #iCnt int = 1
while #iCnt<=4
--(0<len(#sText) and 0<#lBegin and 0<#lEnd)
BEGIN
SET #sText0 = substring(#sText,#lBegin+1,#lEnd-2)
IF #iCnt=1 begin SET #sColumn1=#sText0 end
IF #iCnt=2 begin SET #sColumn2=#sText0 end
IF #iCnt=3 begin SET #sColumn3=#sText0 end
IF #iCnt=4 begin SET #sColumn4=#sText0 end
set #sText = substring(#sText,#lBegin + #lEnd+2,len(#sText))
SET #lBegin = CHARINDEX('''',#sText)
SET #lEnd = charindex('''',
substring(#sText,
CHARINDEX('''',#sText)+1,
len(#sText)))
SET #iCnt = #iCnt+1
END
INSERT
tResults (sColumn1,sColumn2,sColumn3,sColumn4)
VALUES (#sColumn1,#sColumn2,#sColumn3,#sColumn4)
SELECT * FROM tResults
on sql fiddle
You will be able to achieve this using CHARINDEX() and SUBSTRING()
Following example shows for splitting to 2 columns. When it has more columns, query will be get little more complicated. However, you can follow this to build your query.
SELECT OriginalColumn
, SUBSTRING(OriginalColumn, 1,CHARINDEX('x',OriginalColumn,1)-1) AS Column1
, SUBSTRING(OriginalColumn, CHARINDEX('x',OriginalColumn,1) + 1 ,CHARINDEX('x',OriginalColumn,CHARINDEX('x',OriginalColumn,1)-1)) AS Column2
FROM YourTable
I have used "x" as the delimiter in the example. Following is a sample result
try this:
declare #delim char
set #delim = ''''
declare #str nvarchar(max)
declare #substr nvarchar(max)
declare #newstr nvarchar(max)
declare #tmpTable table (partStrings nvarchar(max))
declare #count int
set #count = 0
select #str = <***Your String***>
while(charindex(#delim,#str) != 0)
begin
set #count = #count + 1
Select #substr = substring(#str,1,charindex(#delim,#str)-1)
if((#count % 2) = 0)
begin
insert into #tmpTable values(#substr)
end
Set #newstr = substring(#str,charindex(#delim,#str)+1,len(#str)-charindex(#delim,#str))
set #str = #newstr
end
select partStrings from #tmpTable

SQL Server 2005:charindex starting from the end

I have a string 'some.file.name',I want to grab 'some.file'.
To do that,I need to find the last occurrence of '.' in a string.
My solution is :
declare #someStr varchar(20)
declare #reversedStr varchar(20)
declare #index int
set #someStr = '001.002.003'
set #reversedStr = reverse(#someStr)
set #index = len(#someStr) - charindex('.',#reversedStr)
select left(#someStr,#index)
Well,isn't it too complicated?I was just intented to using 'some.file' in a where-clause.
Anyone has a good idea?
What do you need to do with it?? Do you need to grab the characters after the last occurence of a given delimiter?
If so: reverse the string and search using the normal CHARINDEX:
declare #test varchar(100)
set #test = 'some.file.name'
declare #reversed varchar(100)
set #reversed = REVERSE(#test)
select
REVERSE(SUBSTRING(#reversed, CHARINDEX('.', #reversed)+1, 100))
You'll get back "some.file" - the characters up to the last "." in the original file name.
There's no "LASTCHARINDEX" or anything like that in SQL Server directly. What you might consider doing in SQL Server 2005 and up is great a .NET extension library and deploy it as an assembly into SQL Server - T-SQL is not very strong with string manipulation, whereas .NET really is.
A very simple way is:
SELECT
RIGHT(#str, CHARINDEX('.', REVERSE(#str)) - 1)
This will also work:
DECLARE
#test VARCHAR(100)
SET #test = 'some.file.name'
SELECT
LEFT(#test, LEN(#test) - CHARINDEX('.', REVERSE(#test)))
Take one ')'
declare #test varchar(100)
set #test = 'some.file.name'
select left(#test,charindex('.',#test)+charindex('.',#test)-1)
CREATE FUNCTION [dbo].[Instr] (
-------------------------------------------------------------------------------------------------
-- Name: [dbo].[Instr]
-- Purpose: Find The Nth Value Within A String
-------------------------------------------------------------------------------------------------
-- Revisions:
-- 25-FEB-2011 - HESSR - Initial Revision
-------------------------------------------------------------------------------------------------
-- Parameters:
-- 1) #in_FindString - NVARCHAR(MAX) - INPUT - Input Find String
-- 2) #in_String - NVARCHAR(MAX) - INPUT - Input String
-- 3) #in_StartPos - SMALLINT - INPUT - Position In The String To Start Looking From
-- (If Start Position Is Negative, Search Begins At The End Of The String)
-- (Negative 1 Starts At End Position 1, Negative 3 Starts At End Position Minus 2)
-- 4) #in_Nth - SMALLINT - INPUT - Nth Occurrence To Find The Location For
-------------------------------------------------------------------------------------------------
-- Returns: SMALLINT - Position Of String Segment (Not Found = 0)
-------------------------------------------------------------------------------------------------
#in_FindString NVARCHAR(MAX),
#in_String NVARCHAR(MAX),
#in_StartPos SMALLINT = NULL,
#in_Nth SMALLINT = NULL
)
RETURNS SMALLINT
AS
BEGIN
DECLARE #loc_FindString NVARCHAR(MAX);
DECLARE #loc_String NVARCHAR(MAX);
DECLARE #loc_Position SMALLINT;
DECLARE #loc_StartPos SMALLINT;
DECLARE #loc_Nth SMALLINT;
DECLARE #loc_Idx SMALLINT;
DECLARE #loc_FindLength SMALLINT;
DECLARE #loc_Length SMALLINT;
SET #loc_FindString = #in_FindString;
SET #loc_String = #in_String;
SET #loc_Nth = ISNULL(ABS(#in_Nth), 1);
SET #loc_FindLength = LEN(#loc_FindString+N'.') - 1;
SET #loc_Length = LEN(#loc_String+N'.') - 1;
SET #loc_StartPos = ISNULL(#in_StartPos, 1);
SET #loc_Idx = 0;
IF (#loc_StartPos = ABS(#loc_StartPos))
BEGIN
WHILE (#loc_Idx < #loc_Nth)
BEGIN
SET #loc_Position = CHARINDEX(#loc_FindString,#loc_String,#loc_StartPos);
IF (#loc_Position > 0)
SET #loc_StartPos = #loc_Position + #loc_FindLength
ELSE
SET #loc_Idx = #loc_Nth;
SET #loc_Idx = #loc_Idx + 1;
END;
END
ELSE
BEGIN
SET #loc_StartPos = ABS(#loc_StartPos);
SET #loc_FindString = REVERSE(#in_FindString);
SET #loc_String = REVERSE(#in_String);
WHILE (#loc_Idx < #loc_Nth)
BEGIN
SET #loc_Position = CHARINDEX(#loc_FindString,#loc_String,#loc_StartPos);
IF (#loc_Position > 0)
SET #loc_StartPos = #loc_Position + #loc_FindLength
ELSE
SET #loc_Idx = #loc_Nth;
SET #loc_Idx = #loc_Idx + 1;
END;
IF (#loc_Position > 0)
SET #loc_Position = #loc_Length - #loc_Position + (1 - #loc_FindLength) + 1;
END;
RETURN (#loc_Position);
END;
GO
Here is a shorter version
DECLARE #someStr varchar(20)
set #someStr = '001.002.003'
SELECT REVERSE(Substring(REVERSE(#someStr),CHARINDEX('.', REVERSE(#someStr))+1,20))