Substring select string between two characters - sql-server

The following code
declare #text VARCHAR(MAX)
set #text='[Dim Company].[Company].[23]'
SELECT SUBSTRING(#Text, CHARINDEX('[Dim Company].[Company].[', #Text)
, CHARINDEX(']',#text) - CHARINDEX('[Dim Company].[Company].[', #Text) + Len(']'))
Returns [Dim Company]. I was expecting it to return the integer between the last [] -- in this case 23. How can I get the desired field?

If you know it's always last, why not REVERSE the string, find the value between the first pair of brackets, then REVERSE that result?
Much easier than nesting CHARINDEX calls.

This will give you 23]
SELECT RIGHT(#text, CHARINDEX('[',REVERSE(#text))-1)
This will give you 23
SET #tmp = RIGHT(#text, CHARINDEX('[',REVERSE(#text))-1)
SET #tmp = LEFT(#tmp, LEN(tmp)-1)
fiddle : http://sqlfiddle.com/#!3/d41d8/36013

I agree with mwigdahl, this is bad way of doing things, but this is the answer you seek:
declare #text VARCHAR(MAX)
set #text='[Dim Company].[Company].[23]'
SELECT SUBSTRING(#Text,
LEN('[Dim Company].[Company].[')+1,
LEN(#text)-LEN('[Dim Company].[Company].[')-1)
A better approach is to use the PARSENAME() function. The function's purpose is actually to parse an object name, such as server.schema.table, but since your string looks just like that, we can hijack the function. It's far more efficient, and cleaner than charindex/substring.
declare #text varchar(max), #p1 varchar(max), #p2 varchar(max), #p3 varchar(max)
set #text='[Dim Company].[Company].[23]'
set #p1 = PARSENAME(#text, 3)
set #p2 = PARSENAME(#text, 2)
set #p3 = PARSENAME(#text, 1)
select #p1, #p2, #p3

Related

SQL Server while loop not printing last value

I have below code, why i am not trying to get the last value in the temp table for #waitlistitmeID
10011 is not getting stored, though its len is 19 and it should be inserted.
Need help in the query.
DECLARE #pos INT
DECLARE #len INT
DECLARE #value VARCHAR(MAX)
declare #WaitlistItemID varchar(max)='10008,10009,10010,10011'
declare #MovingWaitListItems table ( WaitlistItemID int, WaitlistItemGUID numeric(16,0))
set #pos = 0
set #len = 0
while CHARINDEX(',', #WaitlistItemID, #pos+1)>0
BEGIN
set #len = CHARINDEX(',', #WaitlistItemID, #pos+1) - #pos
set #value = SUBSTRING(#WaitlistItemID, #pos, #len)
print #pos
print #len
print #value
INSERT INTO #MovingWaitListItems
SELECT WaitlistItemID, WaitlistItemGUID
FROM SXAAMWLWaitList
Where WaitlistItemID = #value
select * from #MovingWaitListItems
set #pos = CHARINDEX(',', #WaitlistItemID, #pos+#len) +1
print #pos
END
For above, i would like to use of xml node method instead of use of loops with substring(), CHARINDEX() function
declare #WaitlistItemID varchar(max)='10008,10009,10010,10011'
declare #MovingWaitListItems table ( WaitlistItemID int, WaitlistItemGUID numeric(16,0))
;with cte as
(
select
a.value('.', 'varchar(max)') [WaitlistItemID] from
(
select CAST('<m>'+REPLACE(#WaitlistItemID, ',', '</m><m>')+'</m>' as xml) as waitlist
) w cross apply waitlist.nodes ('/m') as split(a)
)
INSERT INTO #MovingWaitListItems
select S.WaitlistItemID, S.WaitlistItemGUID from SXAAMWLWaitList S
JOIN CTE C ON C.[WaitlistItemID] = S.WaitlistItemID
select * from #MovingWaitListItems
For the moment I'll give you the benefit of the doubt and assume that there is some good reason for #WaitlistItemID to be a comma-delimited string. Your while loop condition says that processing should continue as long as a comma exists somewhere in the part of the string you haven't parsed yet. Of course, as Juan Carlos Oropeza points out in his answer, this will always be false for the last item in your list, because you haven't placed a comma after the last value (10011).
However, I would not recommend repeating the insert statement after the loop as in Juan's answer, because there's an easy way to avoid the duplication: just reformulate the loop so its condition instead asks whether there is any part of the string you haven't processed yet. For instance:
declare #cursorPosition int = 1;
declare #commaPosition int;
declare #valueLength int;
declare #value varchar(max);
declare #WaitlistItemID varchar(max)='10008,10009,10010,10011';
declare #MovingWaitListItems table (WaitlistItemID int, WaitlistItemGUID numeric(16,0));
while #cursorPosition < len(#WaitlistItemID)
begin
set #commaPosition = charindex(',', #WaitlistItemID, #cursorPosition);
set #valueLength = case
when #commaPosition = 0 then len(#WaitlistItemID) - #cursorPosition + 1
else #commaPosition - #cursorPosition
end;
set #value = substring(#WaitlistItemID, #cursorPosition, #valueLength);
set #cursorPosition = #cursorPosition + #valueLength + 1;
insert #MovingWaitListItems
select WaitlistItemID, WaitlistItemGUID
from SXAAMWLWaitList
where WaitlistItemID = #value;
end;
select * from #MovingWaitListItems;
Hopefully this answers the question of why your loop isn't performing as you expect. The question I have for you is why you're resorting to parsing a delimited string in SQL in the first place. If #WaitlistItemID is a table of identifiers instead of a delimited string, then the equivalent logic is:
declare #WaitlistItemID table (ID int);
insert #WaitlistItemID values (10008),(10009),(10010),(10011);
declare #MovingWaitListItems table (WaitlistItemID int, WaitlistItemGUID numeric(16,0));
insert #MovingWaitListItems
select W.WaitlistItemID, W.WaitlistItemGUID
from
SXAAMWLWaitList W
inner join #WaitlistItemID ID on W.WaitlistItemID = ID.ID;
select * from #MovingWaitListItems;
Aside from being much easier to understand, this is also going to have vastly better performance than the equivalent iterative solution; set-based logic like this is SQL's forte. while loops in SQL are something you should fall back on only when it's absolutely necessary.
If, in your actual application, #MovingWaitListItems needs to be a parameter to a stored procedure (or similar), you can enable that functionality by creating a custom type. For instance:
create type dbo.IdentifierList as table (ID int);
You can use this type for parameters to stored procedures and functions like so:
create procedure DoSomething(#WaitlistItemID dbo.IdentifierList readonly)
as
select W.WaitlistItemID, W.WaitlistItemGUID
from
SXAAMWLWaitList W
inner join #WaitlistItemID ID on W.WaitlistItemID = ID.ID;
And invoke it like this:
declare #WaitlistItemID dbo.IdentifierList;
insert #WaitlistItemID values (10008),(10009),(10010),(10011);
exec DoSomething #WaitlistItemID;
Perhaps you're already aware of all this and there is a good reason for #WaitlistItemID to be a delimited string. For instance, maybe you're maintaining a stored procedure that was written to accept a delimited string as a parameter and you're not able to refactor the caller(s) to use a table-type parameter instead. In that case, I would still recommend a change to your original design: instead of writing the parsing logic directly into this specific application, consider writing yourself a generic function that takes a delimited string and outputs a table, as described in questions like this one, so you can reuse it the next time a similar scenario comes up instead of having to struggle with the parsing logic again.
Imagine if you have a #WaitlistItemID with a single element 10100 you will also skip it because your loop condition will be false.
while CHARINDEX(',', #WaitlistItemID, #pos+1)>0
Same is true for the last element. So you have to add another interaction at the end of the loop
while ...
begin
end
set #len = LEN(#WaitlistItemID)
if #len > 0
BEGIN
set #value = SUBSTRING(#WaitlistItemID, #pos, #len)
INSERT INTO #MovingWaitListItems
SELECT WaitlistItemID, WaitlistItemGUID
FROM SXAAMWLWaitList
Where WaitlistItemID = #value
END
Problem is related to the number of commas i think.
You can add one more item as dummy, you will see 10011 when you add a comma like this:
declare #WaitlistItemID varchar(max)='10008,10009,10010,10011,'
or
declare #WaitlistItemID varchar(max)='10008,10009,10010,10011,0'

Saving sql query that contains arabic into a cell

declare #val nvarchar(max),#H_ARABIC nvarchar(max)
select #val = 'select [settings_key] as N''اسم'' from [settings]'
set #H_ARABIC= #val;
print #H_ARABIC
It is showing results as
select [settings_key] as N'???' from [application_setting] but how can I get this result
select [settings_key] as N'اسم' from [application_setting] I have tried many ways by changing the quotation mark but no use. Pls help
Prefix your string literal with N.
declare #val nvarchar(max),#H_ARABIC nvarchar(max)
select #val = N'select [settings_key] as N''اسم'' from [settings]'
set #H_ARABIC= #val;
print #H_ARABIC

function separate string

I have this question for you.I am working a function which has the whole address in one field.I am trying to separate it.I have started working on the one below and I am having difficulty when I try to work on the zip ,I want to test if there is a zip first at the end and if so I am trying to separate it from the state.Could you please have alook at it?Thanks alot guys as usual I appreciate you support..
declare #var1 varchar(100)='1234 S.Almeda way,Seattle,WA9810'--just an example
,#u int
,#r int
,#var2 varchar(100)
,#var3 varchar(100)
,#Zip varchar(25)
,#var4 varchar(100)=null
set #u = charindex(',', #var1)
set #var2=rtrim(ltrim(substring(#var1, #u+1, 999)))
set #r=CHARINDEX(',',#var2)
set #var3=rtrim(ltrim(substring(#var2, #r+1, 999)))
--set #var4=RIGHT(#var3,5)--not enough
if (len(#var3)>=5 and ISNUMERIC(#var3)=1 )
set #var4=RIGHT(#var3,5)
set rtrim(substring(#var3,1,len(#var3)-5))
else set #var4=''
Here's some sample code you can merge into yours
declare #var1 varchar(100)='1234 S.Almeda way,Seattle,WA9810'--just an example
declare #lastcomma int = len(#var1) - charindex(',', reverse(#var1)+',')
declare #lastPart varchar(100) = substring(#var1, #lastcomma+2, 100)
select #lastPart
declare #zipstart int = patindex('%[0-9]%', #lastpart)
declare #zip varchar(5) = ''
if #zipstart > 0
select #zip = substring(#lastpart, #zipstart, 5), #lastPart = rtrim(substring(#lastpart,1,#zipstart-1))
select #lastpart, #zip
You are obvioulsy looking for a split function, which is not built-in SQL Server.
I've stop reading your code when I saw the name you give to your variables (really bad choices, it should have some kind of meaning)
There are many ways to implement it, I'll pick one randomly from a google search (nah, I'm not ashamed, I don't want to reinvent the wheel)
CREATE FUNCTION dbo.Split(#String varchar(8000), #Delimiter char(1))
returns #temptable TABLE (items varchar(8000))
as
begin
declare #idx int
declare #slice varchar(8000)
select #idx = 1
if len(#String)<1 or #String is null return
while #idx!= 0
begin
set #idx = charindex(#Delimiter,#String)
if #idx!=0
set #slice = left(#String,#idx - 1)
else
set #slice = #String
if(len(#slice)>0)
insert into #temptable(Items) values(#slice)
set #String = right(#String,len(#String) - #idx)
if len(#String) = 0 break
end
return
end
use it this way :
select top 10 * from dbo.split('1234 S.Almeda way,Seattle,WA9810',',')
It'll give you a column with a result in each row
SOURCE : http://blog.logiclabz.com/sql-server/split-function-in-sql-server-to-break-comma-separated-strings-into-table.aspx
You'll find plenty of other example with a quick web search. ;)

substring or rtrim

i have a field called LastWebpage, in the Field it stores the webpage .asp pagename
I have to write a script where i just need to take the jl_AssessmentDirect.asp name instead of 4000_1_jl_AssessmentDirect.asp. How do i get rid of 4000_1_. Please help.
Thanks.
Here are a couple of ways to do this, I assume the data is not always the same, this is just to show you how the functions work
right or replace is my preferred method
DECLARE #v VARCHAR(100)
SELECT #v = '4000_1_jl_AssessmentDirect.asp'
SELECT REPLACE(#v,'4000_1_','')
or
DECLARE #v VARCHAR(100)
SELECT #v = '4000_1_jl_AssessmentDirect.asp'
DECLARE #r VARCHAR(100)
SELECT #r ='4000_1_'
--if you have spaces RTRIM and LTRIM everything
SELECT RIGHT(#v,LEN(#v) -LEN(#r))
If stuff changes, you can dump it in variables
DECLARE #v VARCHAR(100)
SELECT #v = '4000_1_jl_AssessmentDirect.asp'
DECLARE #r VARCHAR(100)
SELECT #r ='4000_1_'
SELECT REPLACE(#v,#r,'')
Ideally you want to update such columns to only have the URL and nothing else
"It depends"
If always "4000_1_", use REPLACE as per SQLMenace's answer.
If a fixed length of any string, use SUBSTRING. No need to work out LENGTH first
SUBSTRING(MyValue, 8, 8000)
If the right hand side is fixed length and the unwanted part is variable length, use RIGHT
If both sides are variable, you'll need something like
SUBSTRING(MyValue, PATINDEX('%[_]1[_]%', MyValue) + 3, 8000)
Edit:
If you always want "jl"...
SUBSTRING(MyValue, PATINDEX('%jl%', MyValue), 8000)
Besides all the suggestions here already you can use stuff.
declare #s varchar(100)
set #s = '4000_1_jl_AssessmentDirect.asp'
select stuff(#s, 1, 7, '')
Remove characters before jl
declare #s varchar(100)
set #s = '4000_1_jl_AssessmentDirect.asp'
select stuff(#s, 1, charindex('jl', #s)-1, '')

How do you count the number of occurrences of a certain substring in a SQL varchar?

I have a column that has values formatted like a,b,c,d. Is there a way to count the number of commas in that value in T-SQL?
The first way that comes to mind is to do it indirectly by replacing the comma with an empty string and comparing the lengths
Declare #string varchar(1000)
Set #string = 'a,b,c,d'
select len(#string) - len(replace(#string, ',', ''))
Quick extension of cmsjr's answer that works for strings with more than one character.
CREATE FUNCTION dbo.CountOccurrencesOfString
(
#searchString nvarchar(max),
#searchTerm nvarchar(max)
)
RETURNS INT
AS
BEGIN
return (LEN(#searchString)-LEN(REPLACE(#searchString,#searchTerm,'')))/LEN(#searchTerm)
END
Usage:
SELECT * FROM MyTable
where dbo.CountOccurrencesOfString(MyColumn, 'MyString') = 1
You can compare the length of the string with one where the commas are removed:
len(value) - len(replace(value,',',''))
The answer by #csmjr has a problem in some instances.
His answer was to do this:
Declare #string varchar(1000)
Set #string = 'a,b,c,d'
select len(#string) - len(replace(#string, ',', ''))
This works in most scenarios, however, try running this:
DECLARE #string VARCHAR(1000)
SET #string = 'a,b,c,d ,'
SELECT LEN(#string) - LEN(REPLACE(#string, ',', ''))
For some reason, REPLACE gets rid of the final comma but ALSO the space just before it (not sure why). This results in a returned value of 5 when you'd expect 4. Here is another way to do this which will work even in this special scenario:
DECLARE #string VARCHAR(1000)
SET #string = 'a,b,c,d ,'
SELECT LEN(REPLACE(#string, ',', '**')) - LEN(#string)
Note that you don't need to use asterisks. Any two-character replacement will do. The idea is that you lengthen the string by one character for each instance of the character you're counting, then subtract the length of the original. It's basically the opposite method of the original answer which doesn't come with the strange trimming side-effect.
Building on #Andrew's solution, you'll get much better performance using a non-procedural table-valued-function and CROSS APPLY:
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
/* Usage:
SELECT t.[YourColumn], c.StringCount
FROM YourDatabase.dbo.YourTable t
CROSS APPLY dbo.CountOccurrencesOfString('your search string', t.[YourColumn]) c
*/
CREATE FUNCTION [dbo].[CountOccurrencesOfString]
(
#searchTerm nvarchar(max),
#searchString nvarchar(max)
)
RETURNS TABLE
AS
RETURN
SELECT (DATALENGTH(#searchString)-DATALENGTH(REPLACE(#searchString,#searchTerm,'')))/NULLIF(DATALENGTH(#searchTerm), 0) AS StringCount
Declare #string varchar(1000)
DECLARE #SearchString varchar(100)
Set #string = 'as as df df as as as'
SET #SearchString = 'as'
select ((len(#string) - len(replace(#string, #SearchString, ''))) -(len(#string) -
len(replace(#string, #SearchString, ''))) % 2) / len(#SearchString)
Accepted answer is correct ,
extending it to use 2 or more character in substring:
Declare #string varchar(1000)
Set #string = 'aa,bb,cc,dd'
Set #substring = 'aa'
select (len(#string) - len(replace(#string, #substring, '')))/len(#substring)
Darrel Lee I think has a pretty good answer. Replace CHARINDEX() with PATINDEX(), and you can do some weak regex searching along a string, too...
Like, say you use this for #pattern:
set #pattern='%[-.|!,'+char(9)+']%'
Why would you maybe want to do something crazy like this?
Say you're loading delimited text strings into a staging table, where the field holding the data is something like a varchar(8000) or nvarchar(max)...
Sometimes it's easier/faster to do ELT (Extract-Load-Transform) with data rather than ETL (Extract-Transform-Load), and one way to do this is to load the delimited records as-is into a staging table, especially if you may want an simpler way to see the exceptional records rather than deal with them as part of an SSIS package...but that's a holy war for a different thread.
If we know there is a limitation on LEN and space, why cant we replace the space first?
Then we know there is no space to confuse LEN.
len(replace(#string, ' ', '-')) - len(replace(replace(#string, ' ', '-'), ',', ''))
Use this code, it is working perfectly.
I have create a sql function that accept two parameters, the first param is the long string that we want to search into it,and it can accept string length up to 1500 character(of course you can extend it or even change it to text datatype).
And the second parameter is the substring that we want to calculate the number of its occurance(its length is up to 200 character, of course you can change it to what your need). and the output is an integer, represent the number of frequency.....enjoy it.
CREATE FUNCTION [dbo].[GetSubstringCount]
(
#InputString nvarchar(1500),
#SubString NVARCHAR(200)
)
RETURNS int
AS
BEGIN
declare #K int , #StrLen int , #Count int , #SubStrLen int
set #SubStrLen = (select len(#SubString))
set #Count = 0
Set #k = 1
set #StrLen =(select len(#InputString))
While #K <= #StrLen
Begin
if ((select substring(#InputString, #K, #SubStrLen)) = #SubString)
begin
if ((select CHARINDEX(#SubString ,#InputString)) > 0)
begin
set #Count = #Count +1
end
end
Set #K=#k+1
end
return #Count
end
In SQL 2017 or higher, you can use this:
declare #hits int = 0
set #hits = (select value from STRING_SPLIT('F609,4DFA,8499',','));
select count(#hits)
Improved version based on top answer and other answers:
Wrapping the string with delimiters ensures that LEN works properly. Making the replace character string one character longer than the match string removes the need for division.
CREATE FUNCTION dbo.MatchCount(#value nvarchar(max), #match nvarchar(max))
RETURNS int
BEGIN
RETURN LEN('[' + REPLACE(#value,#match,REPLICATE('*', LEN('[' + #match + ']') - 1)) + ']') - LEN('['+#value+']')
END
DECLARE #records varchar(400)
SELECT #records = 'a,b,c,d'
select LEN(#records) as 'Before removing Commas' , LEN(#records) - LEN(REPLACE(#records, ',', '')) 'After Removing Commans'
The following should do the trick for both single character and multiple character searches:
CREATE FUNCTION dbo.CountOccurrences
(
#SearchString VARCHAR(1000),
#SearchFor VARCHAR(1000)
)
RETURNS TABLE
AS
RETURN (
SELECT COUNT(*) AS Occurrences
FROM (
SELECT ROW_NUMBER() OVER (ORDER BY O.object_id) AS n
FROM sys.objects AS O
) AS N
JOIN (
VALUES (#SearchString)
) AS S (SearchString)
ON
SUBSTRING(S.SearchString, N.n, LEN(#SearchFor)) = #SearchFor
);
GO
---------------------------------------------------------------------------------------
-- Test the function for single and multiple character searches
---------------------------------------------------------------------------------------
DECLARE #SearchForComma VARCHAR(10) = ',',
#SearchForCharacters VARCHAR(10) = 'de';
DECLARE #TestTable TABLE
(
TestData VARCHAR(30) NOT NULL
);
INSERT INTO #TestTable
(
TestData
)
VALUES
('a,b,c,de,de ,d e'),
('abc,de,hijk,,'),
(',,a,b,cde,,');
SELECT TT.TestData,
CO.Occurrences AS CommaOccurrences,
CO2.Occurrences AS CharacterOccurrences
FROM #TestTable AS TT
OUTER APPLY dbo.CountOccurrences(TT.TestData, #SearchForComma) AS CO
OUTER APPLY dbo.CountOccurrences(TT.TestData, #SearchForCharacters) AS CO2;
The function can be simplified a bit using a table of numbers (dbo.Nums):
RETURN (
SELECT COUNT(*) AS Occurrences
FROM dbo.Nums AS N
JOIN (
VALUES (#SearchString)
) AS S (SearchString)
ON
SUBSTRING(S.SearchString, N.n, LEN(#SearchFor)) = #SearchFor
);
I finally write this function that should cover all the possible situations, adding a char prefix and suffix to the input. this char is evaluated to be different to any of the char conteined in the search parameter, so it can't affect the result.
CREATE FUNCTION [dbo].[CountOccurrency]
(
#Input nvarchar(max),
#Search nvarchar(max)
)
RETURNS int AS
BEGIN
declare #SearhLength as int = len('-' + #Search + '-') -2;
declare #conteinerIndex as int = 255;
declare #conteiner as char(1) = char(#conteinerIndex);
WHILE ((CHARINDEX(#conteiner, #Search)>0) and (#conteinerIndex>0))
BEGIN
set #conteinerIndex = #conteinerIndex-1;
set #conteiner = char(#conteinerIndex);
END;
set #Input = #conteiner + #Input + #conteiner
RETURN (len(#Input) - len(replace(#Input, #Search, ''))) / #SearhLength
END
usage
select dbo.CountOccurrency('a,b,c,d ,', ',')
Declare #MainStr nvarchar(200)
Declare #SubStr nvarchar(10)
Set #MainStr = 'nikhildfdfdfuzxsznikhilweszxnikhil'
Set #SubStr = 'nikhil'
Select (Len(#MainStr) - Len(REPLACE(#MainStr,#SubStr,'')))/Len(#SubStr)
this T-SQL code finds and prints all occurrences of pattern #p in sentence #s. you can do any processing on the sentence afterward.
declare #old_hit int = 0
declare #hit int = 0
declare #i int = 0
declare #s varchar(max)='alibcalirezaalivisualization'
declare #p varchar(max)='ali'
while #i<len(#s)
begin
set #hit=charindex(#p,#s,#i)
if #hit>#old_hit
begin
set #old_hit =#hit
set #i=#hit+1
print #hit
end
else
break
end
the result is:
1
6
13
20
I ended up using a CTE table for this,
CREATE TABLE #test (
[id] int,
[field] nvarchar(500)
)
INSERT INTO #test ([id], [field])
VALUES (1, 'this is a test string http://url, and https://google.com'),
(2, 'another string, hello world http://example.com'),
(3, 'a string with no url')
SELECT *
FROM #test
;WITH URL_count_cte ([id], [url_index], [field])
AS
(
SELECT [id], CHARINDEX('http', [field], 0)+1 AS [url_index], [field]
FROM #test AS [t]
WHERE CHARINDEX('http', [field], 0) != 0
UNION ALL
SELECT [id], CHARINDEX('http', [field], [url_index])+1 AS [url_index], [field]
FROM URL_count_cte
WHERE CHARINDEX('http', [field], [url_index]) > 0
)
-- total urls
SELECT COUNT(1)
FROM URL_count_cte
-- urls per row
SELECT [id], COUNT(1) AS [url_count]
FROM URL_count_cte
GROUP BY [id]
Using this function, you can get the number of repetitions of words in a text.
/****** Object: UserDefinedFunction [dbo].[fn_getCountKeywords] Script Date: 22/11/2021 17:52:00 ******/
DROP FUNCTION IF EXISTS [dbo].[fn_getCountKeywords]
GO
/****** Object: UserDefinedFunction [dbo].[fn_getCountKeywords] Script Date: 2211/2021 17:52:00 ******/
SET ANSI_NULLS OFF
GO
SET QUOTED_IDENTIFIER ON
GO
-- =============================================
-- Author: m_Khezrian
-- Create date: 2021/11/22-17:52
-- Description: Return Count Keywords In Input Text
-- =============================================
Create OR Alter Function [dbo].[fn_getCountKeywords]
(#Text nvarchar(max)
,#Keywords nvarchar(max)
)
RETURNS #Result TABLE
(
[ID] int Not Null IDENTITY PRIMARY KEY
,[Keyword] nvarchar(max) Not Null
,[Cnt] int Not Null Default(0)
)
/*With ENCRYPTION*/ As
Begin
Declare #Key nvarchar(max);
Declare #Cnt int;
Declare #I int;
Set #I = 0 ;
--Set #Text = QUOTENAME(#Text);
Insert Into #Result
([Keyword])
Select Trim([value])
From String_Split(#Keywords,N',')
Group By [value]
Order By Len([value]) Desc;
Declare CntKey_Cursor Insensitive Cursor For
Select [Keyword]
From #Result
Order By [ID];
Open CntKey_Cursor;
Fetch Next From CntKey_Cursor Into #Key;
While (##Fetch_STATUS = 0) Begin
Set #Cnt = 0;
While (PatIndex(N'%'+#Key+'%',#Text) > 0) Begin
Set #Cnt += 1;
Set #I += 1 ;
Set #Text = Stuff(#Text,PatIndex(N'%'+#Key+'%',#Text),len(#Key),N'{'+Convert(nvarchar,#I)+'}');
--Set #Text = Replace(#Text,#Key,N'{'+Convert(nvarchar,#I)+'}');
End--While
Update #Result
Set [Cnt] = #Cnt
Where ([Keyword] = #Key);
Fetch Next From CntKey_Cursor Into #Key;
End--While
Close CntKey_Cursor;
Deallocate CntKey_Cursor;
Return
End
GO
--Test
Select *
From dbo.fn_getCountKeywords(
N'<U+0001F4E3> MARKET IMPACT Euro area Euro CPIarea annual inflation up to 3.0% MaCPIRKET forex'
,N'CPI ,core,MaRKET , Euro area'
)
Go
Reference https://learn.microsoft.com/en-us/sql/t-sql/functions/string-split-transact-sql?view=sql-server-ver15
Example:
SELECT s.*
,s.[Number1] - (SELECT COUNT(Value)
FROM string_split(s.[StringColumn],',')
WHERE RTRIM(VALUE) <> '')
FROM TableName AS s
Applies to: SQL Server 2016 (13.x) and later
You can use the following stored procedure to fetch , values.
IF EXISTS (SELECT * FROM sys.objects
WHERE object_id = OBJECT_ID(N'[dbo].[sp_parsedata]') AND type in (N'P', N'PC'))
DROP PROCEDURE [dbo].[sp_parsedata]
GO
create procedure sp_parsedata
(#cid integer,#st varchar(1000))
as
declare #coid integer
declare #c integer
declare #c1 integer
select #c1=len(#st) - len(replace(#st, ',', ''))
set #c=0
delete from table1 where complainid=#cid;
while (#c<=#c1)
begin
if (#c<#c1)
begin
select #coid=cast(replace(left(#st,CHARINDEX(',',#st,1)),',','') as integer)
select #st=SUBSTRING(#st,CHARINDEX(',',#st,1)+1,LEN(#st))
end
else
begin
select #coid=cast(#st as integer)
end
insert into table1(complainid,courtid) values(#cid,#coid)
set #c=#c+1
end
The Replace/Len test is cute, but probably very inefficient (especially in terms of memory).
A simple function with a loop will do the job.
CREATE FUNCTION [dbo].[fn_Occurences]
(
#pattern varchar(255),
#expression varchar(max)
)
RETURNS int
AS
BEGIN
DECLARE #Result int = 0;
DECLARE #index BigInt = 0
DECLARE #patLen int = len(#pattern)
SET #index = CHARINDEX(#pattern, #expression, #index)
While #index > 0
BEGIN
SET #Result = #Result + 1;
SET #index = CHARINDEX(#pattern, #expression, #index + #patLen)
END
RETURN #Result
END
Perhaps you should not store data that way. It is a bad practice to ever store a comma delimited list in a field. IT is very inefficient for querying. This should be a related table.

Resources