Spiting filter values into conditions sql - sql

I have a filter and condition in a function, which works for only one condition
i:e '='
I want it to work for all condition like ' IN', ' >=', '<='
Here is the Code
declare #filter VARCHAR(1000)
DECLARE #TempFilter VARCHAR(1000)
declare #Condition VARCHAR(1000)
set #Condition='Blocked'
SET #Filter=N'Blocked=0 and TYPE = 2 and ID = 1635729'
SET #Condition=#Condition+'='
SELECT
#TempFilter=SUBSTRING(#Filter,CHARINDEX(#Condition,#Filter),LEN(#Filter))
IF CHARINDEX('and',#TempFilter)=0
BEGIN
SET #Filter=SUBSTRING(#Filter,CHARINDEX(#Condition,#Filter)+LEN(#Condition),
LEN(#Filter)-LEN(#Condition)-LEN(#TempFilter))
END
ELSE
BEGIN
SET #Filter=SUBSTRING(#Filter,CHARINDEX(#Condition,#Filter)+LEN(#Condition),
CHARINDEX(' ',#TempFilter)-LEN(#Condition))
END
Please help or suggest.

Can you test this code
DECLARE #tempFilter VARCHAR(1000)
declare #condition VARCHAR(1000)
declare #filter VARCHAR(1000)
declare #operator VARCHAR(1000)
declare #trimmedFilter VARCHAR(1000)
set #Condition='Blocked'
SET #filter=N'Blocked IN(0) and TYPE > = 2 and ID IN (1635729,15454)'
WHILE LEN(#Filter) > 0
BEGIN
IF CHARINDEX(' and',#filter)<> 0
begin
SET #TempFilter = RIGHT ( #filter , LEN(#filter) - CHARINDEX(' and',#filter)-4)
SET #filter = LEFT ( #filter , CHARINDEX(' and',#filter))
end
SET #trimmedFilter = REPLACE(#filter,' ','')
set #operator =
case
when CHARINDEX('NOTIN(',#trimmedFilter) <> 0 then 'NOTIN'
when CHARINDEX('IN(',#trimmedFilter) <> 0 then 'IN'
when CHARINDEX('>=',#trimmedFilter) <> 0 then '>='
when CHARINDEX('<=',#trimmedFilter) <> 0 then '<='
else '='
end
IF CHARINDEX(#Condition,#filter) <> 0
BEGIN
SET #filter = REPLACE(RIGHT(#trimmedFilter,LEN(#trimmedFilter) - CHARINDEX(#operator,#trimmedFilter)+1), 'NOTIN', 'NOT IN')
BREAK
END
ELSE
BEGIN
SET #filter = #TempFilter
CONTINUE
END
END

Related

Error Pass from nested MSSQL procedure to parent procedure

I have one parent stored procedure and one nested stored procedure. Parent Stored procedure calls the nested stored procedure on loop. Now when there is certain condition matches I have raised the error. When this error is raised I want to stop all the process and return the error.
CREATE Proc [dbo].[Usp_GenSalarySheet](#SalData [HRM].UTDT_SalaryData ReadOnly)
AS
set nocount on
DECLARE #SMT NVARCHAR(MAX)
SET #SMT = 'Create Table ##SalarySheet (StaffID INT,FullName NVARCHAR(1024),PresentDays NVARCHAR(1024),Absent NVARCHAR(1024),Department NVARCHAR(1024),Designation NVARCHAR(1024),'
DECLARE #HopName nvarchar(max)
Declare HOPCursor cursor for select ID from HRM.tbl_HOP
OPEN HOPCursor
FETCH NEXT FROM HOPCursor INTO #HopName
WHILE ##FETCH_STATUS = 0
BEGIN
SET #SMT = #SMT + ' [' + #HopName + '] DECIMAL(19,7),'
FETCH NEXT FROM HOPCursor into #HopName
END
SET #SMT = #SMT + '[Total] DECIMAL(19,7))'
CLOSE HOPCursor
DEALLOCATE HOPCursor
print (#smt)
exec (#SMT)
select * into #temp from #SalData
Declare #TopID INT
While (Select Count(*) From #Temp) > 0
Begin
Select Top 1 #TopID = StaffID From #temp
Declare #StaffID INT =(select top 1 StaffID from #temp)
Declare #StaffName NVARCHAR(1024) = (SELECT TOP 1 FullName FROM #temp)
Declare #WorkingDays Int = (SELECT top 1 WorkingDays from #temp)
Declare #Leave INT = (SELECT top 1 [Absent] from #temp)
INSERT INTO ##SalarySheet(StaffID,FullName,[Absent]) values(#StaffID,#StaffName,#Leave)
DECLARE #HOPType INT
DECLARE #Value Decimal(19,7)
DECLARE #CalcVal DECIMAL(19,7) = 0
DECLARE #Formula NVARCHAR(MAX)
DECLARE #Total DECIMAL(19,7)
DECLARE #PayEvery INT
DECLARE #Round Int
Declare HOPList Cursor for SELECT ID,HOPType,Value,Formula,RoundOff,PayEvery FROM HRM.Tbl_HOP order by Schedule
open HOPList
FETCH NEXT FROM HOPList INTO #HopName,#HOPType,#Value,#Formula,#Round,#PayEvery
WHILE ##FETCH_STATUS = 0
BEGIN
if exists(select * from HRM.[Tbl_ContractHOPDetails] where PersonalDetailsID = #StaffID and HOPID = #HopName)
print('select * from HRM.[Tbl_ContractHOPDetails] where PersonalDetailsID = ' + convert(varchar(max), #StaffID) + ' and HOPID =' + convert(varchar(max),#HopName))
begin
if(#HOPType=51)
begin
exec HRM.Usp_GetSalaryValueFromFormula #StaffID,#Formula,#HOPType,#Leave,#WorkingDays,#Value output
set #HOPType= 50
end
if(#HOPType=50)
begin
set #CalcVal = #value
END
IF(#HOPType=38)
BEGIN
SET #CalcVal = #Value - ((#Value/#WorkingDays) * #Leave)
END
if(#PayEvery= 40)
begin
set #CalcVal = ((#CalcVal * #WorkingDays) - (#CalcVal * #Leave))
end
if(#Round = 45)
begin
set #CalcVal = round(#CalcVal,2)
end
else if(#Round = 46)
begin
set #CalcVal = CEILING(#CalcVal)
end
else if(#Round = 47)
begin
set #CalcVal = FLOOR(#CalcVal)
end
set #SMT ='UPDATE ##SalarySheet SET [' + #HopName + '] = ' + cast(#CalcVal as nvarchar(max)) + ' where StaffID = ' + cast(#StaffID as nvarchar(max))
exec (#smt)
end
SET #CalcVal = 0
FETCH NEXT FROM HOPList INTO #HopName,#HOPType,#Value,#Formula,#Round,#PayEvery
END
close HOPList
DEALLOCATE HOPList
set #SMT ='UPDATE ##SalarySheet SET [Total] = ' + cast(#Total as nvarchar(max)) + ' where StaffID = ' + cast(#StaffID as nvarchar(max))
exec (#smt)
Delete #temp Where StaffID = #TopID
end
select * from ##SalarySheet
drop table ##SalarySheet
This is my parent Stored Procudere and nested procedure is as follow:
CREATE proc [HRM].[Usp_GetSalaryValueFromFormula](#StaffID INT,#val nvarchar(max),#HOPType INT,#Leave INT,#WorkingDays INT, #GetResult Decimal(19,7) output)
as
set nocount on
Declare #Formula Varchar(max)
declare #initial INT =0
declare #final INT =0
Declare #DataVal NVARCHAR(MAX) -- set the value from HOP table
declare #FieldVal nvarchar(max)
declare #cnt int = 0
Declare #Complete Int =CHARINDEX ('[',#val,0)
while (#Complete <> 0)
begin
set #initial = CHARINDEX ('[',#val,0)
set #final = CHARINDEX(']',#val,0)
set #FieldVal = SUBSTRING(#val,#initial,(#final-#initial) + 1)
if len(#FieldVal)<>0
begin
select #HOPType = HOPType, #DataVal= ( case when HOPType = 51 then [Formula] else cast([Value] as nvarchar(max)) end) from HRM.Tbl_ContractHOPDetails where PersonalDetailsID = #StaffID and HOPID in(select ID from HRM.tbl_HOP where HOPName = replace(replace(#fieldVal,'[',''),']',''))
if (#DataVal is null or #DataVal ='')
begin
RAISERROR ('Nested HOP is not defined.',11,1)
RETURN
end
print(#DataVal)
if ISNUMERIC(#DataVal)=1
begin
if(#HOPType = 38)
begin
SET #DataVal = cast(#DataVal as decimal(19,7)) - ((cast(#DataVal as decimal(19,7))/#WorkingDays) * #Leave)
end
end
set #val = replace(#val,#fieldVal,#DataVal)
set #fieldVal= ''
set #DataVal = ''
end
set #Complete = CHARINDEX ('[',#val,0)
set #fieldVal =''
set #final =0
set #initial = 0
end
SET #Complete =CHARINDEX ('{',#val,0)
while (#Complete <> 0)
BEGIN
set #initial = CHARINDEX ('{',#val,0)
set #final = CHARINDEX('}',#val,0)
set #FieldVal = SUBSTRING(#val,#initial+1,(#final-#initial)-1)
if len(#FieldVal)<>0
begin
set #DataVal = isnumeric((SELECT 0 FROM [HRM].Tbl_StaffTag where CValue = #FieldVal and StaffID = #StaffID))
set #FieldVal = '{' + #FieldVal + '}'
set #val = replace(#val,#fieldVal,#DataVal)
set #fieldVal= ''
set #DataVal = ''
end
set #Complete = CHARINDEX ('{',#val,0)
set #final =0
set #initial = 0
END
DECLARE #RetrunVal DECIMAL(19,7)
declare #ParmDefinition Nvarchar(512) = '#GetVal decimal(19,7) OUTPUT'
Declare #SMT NVARCHAR(MAX) = ' SET #GetVal = ' + #val
EXECUTE sp_executeSQL #Smt, #ParmDefinition, #GetVal =#RetrunVal OUTPUT
set #GetResult = #RetrunVal
But in current situation it raises error and again from the main procedure it runs next step of loop. But I want to terminate the complete process after this raiserror
Kindly help me
My guess is that RaiseError throws the control back to the caller, which might make the Return statement unreachable. The caller (loop) continues with next iteration.

search in a string creditcard numeric value

I want to find a credit card numeric value in a sql string.
for example;
DECLARE #value1 NVARCHAR(MAX) = 'The payment is the place 1234567812345678'
DECLARE #value2 NVARCHAR(MAX) = 'The payment is the place 123456aa7812345678'
DECLARE #value3 NVARCHAR(MAX) = 'The payment1234567812345678is the place'
The result should be :
#value1Result 1234567812345678
#value2Result NULL
#value3Result 1234567812345678
16 digits must be together without space.
How to do this in a sql script or a function?
edit :
if I want to find these 2 credit card value.
#value4 = 'card 1 is : 4034349183539301 and the other one is 3456123485697865'
how should I implement the scripts?
You can use PathIndex as
PATINDEX('%[0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9]%', yourStr)
if the result is 0 then it doesnt containg 16 digits other was it contains.
It can be used withing a Where statement or Select statement based on your needs
You can write as:
SELECT case when Len(LEFT(subsrt, PATINDEX('%[^0-9]%', subsrt + 't') - 1)) = 16
then LEFT(subsrt, PATINDEX('%[^0-9]%', subsrt + 't') - 1)
else ''
end
FROM (
SELECT subsrt = SUBSTRING(string, pos, LEN(string))
FROM (
SELECT string, pos = PATINDEX('%[0-9]%', string)
FROM table1
) d
) t
Demo
DECLARE #value1 NVARCHAR(MAX) = 'card 1 is : 4034349183539301 and the other one is 3456123485697865'
DECLARE #Lenght INT
,#Count INT
,#Candidate CHAR
,#cNum INT
,#result VARCHAR(16)
SELECT #Count = 1
SELECT #cNum = 0
SELECT #result = ''
SELECT #Lenght = LEN(#value1)
WHILE #Count <= #Lenght
BEGIN
SELECT #Candidate = SUBSTRING(#value1, #Count, 1)
IF #Candidate != ' '
AND ISNUMERIC(#Candidate) = 1
BEGIN
SET #cNum = #cNum + 1
SET #result = #result + #Candidate
END
ELSE
BEGIN
SET #cNum = 1
SET #result = ''
END
IF #cNum > 16
BEGIN
SELECT #result 'Credit Number'
END
SET #Count = #Count + 1
END
There you go kind sir.
DECLARE
#value3 NVARCHAR(MAX) = 'The payment1234567812345678is the place',
#MaxCount int,
#Count int,
#Numbers NVARCHAR(100)
SELECT #Count = 1
SELECT #Numbers = ''
SELECT #MaxCount = LEN(#value3)
WHILE #Count <= #MaxCount
BEGIN
IF (UNICODE(SUBSTRING(#value3,#Count,1)) >= 48 AND UNICODE(SUBSTRING(#value3,#Count,1)) <=57)
SELECT #Numbers = #Numbers + SUBSTRING(#value3,#Count,1)
SELECT #Count = #Count + 1
END
PRINT #Numbers
You can make this as a function if you are planning to use it a lot.

Invalid length parameter passed to the LEFT or SUBSTRING function

Following is my query and it works fine when I have like TRAILER_MAKE_MODEL 'testing ~ testing, test ~ testq,' ends with comma but can't handle 'testing ~ testing, test ~ testq' same as for other variable TRAILER_IDV. I tried my best but cant work it out any help would be appreciated.
My aim is to get the comma separated value for xml.
DECLARE #TRAILER_MAKE_MODEL VARCHAR(MAX)
DECLARE #TRAILER_IDV VARCHAR(MAX)
DECLARE #USER_TYPE VARCHAR(MAX)
DECLARE #START_INDEX_1 INT
DECLARE #START_INDEX_4 INT
DECLARE #END_INDEX_1 INT
DECLARE #END_INDEX_4 INT
DECLARE #VALUE VARCHAR(50)
DECLARE #QUERY VARCHAR(MAX)
set #TRAILER_MAKE_MODEL='testing ~ testing, test ~ testq,'
set #TRAILER_IDV='3500, 3400,'
set #USER_TYPE='MOBILE'
set #QUERY = ''
set #START_INDEX_1 = 1
set #START_INDEX_4 = 1
set #END_INDEX_1 = 0
if ISNULL(#TRAILER_MAKE_MODEL,'') <> ''
begin
WHILE #START_INDEX_1 > 0 and #START_INDEX_1 < len(#TRAILER_MAKE_MODEL)
BEGIN
SET #END_INDEX_1 = CHARINDEX(',',#TRAILER_MAKE_MODEL,#START_INDEX_1)
if #END_INDEX_1 = 0 and #START_INDEX_1 = 1
Begin
SET #END_INDEX_1 = len(#TRAILER_MAKE_MODEL)
END
if #USER_TYPE <> 'MOBILE'
Begin
SET #END_INDEX_1 = #END_INDEX_1 +1
End
SET #VALUE = SUBSTRING(#TRAILER_MAKE_MODEL,#START_INDEX_1,#END_INDEX_1 - #START_INDEX_1)
SET #QUERY = #QUERY + 'UNION ALL SELECT ''' + #VALUE + ''' TRAILER_MAKE_MODEL'
SET #END_INDEX_4 = CHARINDEX(',',#TRAILER_IDV,#START_INDEX_4)
if #END_INDEX_4 = 0 and #START_INDEX_4 = 1
Begin
SET #END_INDEX_4 = len(#TRAILER_IDV)
END
if #USER_TYPE <> 'MOBILE'
Begin
SET #END_INDEX_4 = #END_INDEX_4 +1
End
SET #VALUE = SUBSTRING(#TRAILER_IDV,#START_INDEX_4,#END_INDEX_4 - #START_INDEX_4)
SET #QUERY = #QUERY + ',' + #VALUE + 'TRAILER_IDV '
print #QUERY
SET #START_INDEX_1 = #END_INDEX_1 + 1
SET #START_INDEX_4 = #END_INDEX_4 + 1
END
select #QUERY=substring(#QUERY, 10, LEN(#QUERY) - 9)
EXEC (#QUERY)
END
You already have a lot of code here so two extra lines where you assign a comma at the end of each string should probably not slow things down for you or make the code less maintainable.
SET #TRAILER_MAKE_MODEL += ',';
SET #TRAILER_IDV += ',';
I don't really understand what your code does but to get the result you are getting you can use a split string function that returns the index of the item like this.
select T1.Item as TRAILER_MAKE_MODEL,
T2.Item as TRAILER_IDV
from dbo.SplitString(#TRAILER_MAKE_MODEL, ',') as T1
inner join dbo.SplitString(#TRAILER_IDV, ',') as T2
on T1.ItemNumber = T2.ItemNumber

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 Split function that handles string with delimeter appearing between text qualifiers?

There are several SQL split functions, from loop driven, to using xml commands, and even using a numbers table. I haven't found one that supports text qualifiers.
Using the example string below, I would like to split on ",", but not when it appears between double or single quotes.
Example data:
jsmith#anywhere.com, "Sally \"Heat\" Jones" <sally#anywhere.com>, "Mark Jones" <mjones#anywhere.com>, "Stone, Ron" <rstone#anywhere.com>
Should return a table:
jsmith#anywhere.com
"Sally \"Heat\" Jones" <sally#anywhere.com>
"Mark Jones" <mjones#anywhere.com>
"Stone, Ron" <rstone#anywhere.com>
I know this is a complex query/function, but any suggestions or any guidance would be mucho appreciated.
Here is my solution:
CREATE FUNCTION fnSplitString
(
#input nvarchar(MAX)
)
RETURNS #emails TABLE
(
email nvarchar(MAX)
)
AS
BEGIN
DECLARE #len int = LEN(#input)
DECLARE #pos int = 1;
DECLARE #start int = 1;
DECLARE #ignore bit = 0;
WHILE(#pos<=#len)
BEGIN
DECLARE #ch nchar(1) = SUBSTRING(#input, #pos, 1);
IF ( #ch = '"' or #ch = '''')
BEGIN
SET #ignore = 1 - #ignore;
END
IF (#ch = ',' AND #ignore = 0)
BEGIN
INSERT #emails VALUES (SUBSTRING(#input, #start, #pos-#start));
SET #start = #pos+1;
END
SET #pos = #pos + 1;
END
IF (#start<>#pos)
BEGIN
INSERT #emails VALUES (SUBSTRING(#input, #start, #pos-#start));
END
RETURN
END
GO
DECLARE #input nvarchar(max) = 'jsmith#anywhere.com, "Sally \"Heat\" Jones" <sally#anywhere.com>, "Mark Jones" <mjones#anywhere.com>, "Stone, Ron" <rstone#anywhere.com>';
select * from fnSplitString(#input)
CREATE FUNCTION [dbo].[udfSplit]
(
#nvcString nvarchar(max),
#nvcDelimiter nvarchar(1),
#nvcTQ nvarchar(1)
)
RETURNS #tblTokens TABLE (
Token nvarchar(max)
)
AS
BEGIN
DECLARE #intCounter int
DECLARE #nvcToken nvarchar(4000)
DECLARE #nvcCurrentChar nvarchar(1)
DECLARE #intStart int
IF #nvcString <> ''
BEGIN
SET #intCounter = 1
SET #nvcToken = ''
SET #intStart = 0
--Loop through each character of the string
WHILE #intCounter <= LEN(#nvcString)
BEGIN
SET #nvcCurrentChar = SUBSTRING(#nvcString, #intCounter, 1)
--If current char is TQ
IF #nvcCurrentChar = #nvcTQ
BEGIN
--Concatonate to token
SET #nvcToken = #nvcToken + #nvcCurrentChar
--If this is the end TQ
IF #intStart <> 0
BEGIN
--Fix TQ
SET #nvcToken = dbo.udfRemoveTQFromToken(#nvcToken, #nvcTQ)
IF #nvcToken <> ''
BEGIN
INSERT INTO #tblTokens (Token) VALUES (#nvcToken)
SET #nvcToken = ''
END
--Reset TQ
SET #intStart = 0
END
ELSE
BEGIN
SET #nvcToken = dbo.udfRemoveTQFromToken(#nvcToken, #nvcTQ)
IF #nvcToken <> ''
BEGIN
INSERT INTO #tblTokens (Token) VALUES (#nvcToken)
SET #nvcToken = ''
END
--Mark TQ start position
SET #intStart = #intCounter
END
END
ELSE IF #intStart = 0 AND #nvcCurrentChar = #nvcDelimiter
BEGIN
--If not inside TQ, and char is Delimiter
SET #nvcToken = dbo.udfRemoveTQFromToken(#nvcToken, #nvcTQ)
IF #nvcToken <> ''
BEGIN
INSERT INTO #tblTokens (Token) VALUES (#nvcToken)
SET #nvcToken = ''
END
END
ELSE
BEGIN
--Current char is not TQ or Delim, add to current token
SET #nvcToken = #nvcToken + #nvcCurrentChar
END
SET #intCounter = #intCounter + 1
END
END
SET #nvcToken = dbo.udfRemoveTQFromToken(#nvcToken, #nvcTQ)
IF #nvcToken <> ''
BEGIN
--Current Token has not been added to table
INSERT INTO #tblTokens (Token) VALUES (#nvcToken)
END
RETURN
END
GO
CREATE FUNCTION [dbo].[udfRemoveTQFromToken]
(
#nvcToken nvarchar(4000),
#nvcTQ nvarchar(1)
)
RETURNS nvarchar(4000) AS
BEGIN
DECLARE #nvcReturn nvarchar(4000)
--Trim token, needs to be done first,
--as we dont want to trim any spaces within the TQ
--unless it was malformed
SET #nvcReturn = LTRIM(RTRIM(#nvcToken))
--If Left char is TQ
IF LEFT(#nvcReturn, 1) = #nvcTQ
BEGIN
--Though both cases perform the removal of the left most char (opening TQ)
--We need to perform a trim after removal ONLY if it was malformed
IF RIGHT(#nvcReturn, 1) <> #nvcTQ
BEGIN
--But no matching end TQ, malformed
--fix by removing left most char (the opening TQ)
SET #nvcReturn = RIGHT(#nvcReturn, LEN(#nvcReturn) - 1)
--Reapply the LTRIM, incase there were spaces after the opening TQ
SET #nvcReturn = LTRIM(#nvcReturn)
END
ELSE
BEGIN
--has matching end TQ, well-formed
--fix by removing left most char (the opening TQ)
SET #nvcReturn = RIGHT(#nvcReturn, LEN(#nvcReturn) - 1)
END
END
--Remove the right most char (the closing TQ)
IF RIGHT(#nvcReturn, 1) = #nvcTQ
SET #nvcReturn = LEFT(#nvcReturn, LEN(#nvcReturn) - 1)
RETURN #nvcReturn
END
This is a quick solution, and it is less than perfect, it has no stack, so it will treat the comma inside the quotes as the delimiter.
alter function fnSplit
(
#Delim char(1),
#List nvarchar(4000)
)
returns table as
return
with
Strings(PosIdx) as
(
select 1
union all
select PosIdx + 1 from Strings where PosIdx < 4000
)
select
ltrim(rtrim(substring(#List, PosIdx, charindex(#Delim, #List + #Delim, PosIdx) - PosIdx))) as value
from
Strings
where
PosIdx <= convert(int, len(#List))
and substring(#Delim + #List, PosIdx, 1) = #Delim
go
select * from fnSplit(',', 'jsmith#anywhere.com, "Sally \"Heat\" Jones" <sally#anywhere.com>, "Mark Jones" <mjones#anywhere.com>, "Stone, Ron" <rstone#anywhere.com>')
option (maxrecursion 0)