SQL how to do a LIKE search on each value of a declared variable - sql

I have a query where I am trying to do a LIKE search on each value of a declared variable, instead of doing a like search on the entire field value/string.
Example:
DECLARE #name VARCHAR(30)
SET #name = 'John Smith'
SELECT name FROM customers WHERE name like '%'+ #name + '%'
The record I am looking for is "John and Jane Smith". The query above returns NO result. If the user searches just 'John' OR just 'Smith' there are too many results returned.
I am trying to get the query to search like the query below:
SELECT name from customers WHERE name LIKE '%John% %Smith%'
I've searched for many options but not sure if my search terms are not correct, I have yet to find a solution.

I would try replacing spaces in your #name with '% %'
Something like
SET #nameFilter = REPLACE(#name,' ','% %')
SELECT name FROM customers WHERE name like '%'+ # nameFilter + '%'

A full-text search seems like the best approach. But you can approximate this at the word level by splitting the search term and looking for each individual word:
with words as (
select value as word
from string_split(#name)
)
select c.name
from customers c cross apply
(select count(*) as cnt
from words w
where c.name like '%' + c.word + '%'
) w
where w.cnt = (select count(*) from words);
This uses the string_split() functionality available in more recent versions of SQL Server. There are online versions of the function for older versions.

This was answered/accepted before I could post and what #sugar2Code posted is how I would do it.
That said, I was unclear if you wanted both the first and last name needed to be similar or just one of them. What I put together will allow you to decide using a parameter.
-- Sample Data
DECLARE #t TABLE (CustomerName VARCHAR(30))
INSERT #t VALUES('Johny Smith'),('Freddie Roach'),('Mr. Smithers'),('Johnathan Smithe');
-- User Arguments
DECLARE
#name VARCHAR(30) = 'John Smith',
#partialmatch BIT = 1;
-- Dynamic Solution
SELECT
t.CustomerName,
FNMatch = SIGN(pos.F),
LNMatch = SIGN(pos.L)
FROM #t AS t
CROSS JOIN
(
SELECT SUBSTRING(#name,1,f.Mid-1), SUBSTRING(#name,f.Mid+1,8000)
FROM (VALUES(CHARINDEX(' ',#name))) AS f(Mid)
) AS f(FName,LName)
CROSS APPLY (VALUES (CHARINDEX(f.FName,t.CustomerName), CHARINDEX(f.LName,t.CustomerName))) AS pos(F,L)
WHERE (#partialmatch = 0 AND pos.F*pos.L > 0)
OR (#partialmatch = 1 AND pos.F+pos.L > 0);
When #partialmatch = 1 you get:
CustomerName FNMatch LNMatch
------------------------------ ----------- -----------
Johny Smith 1 1
Mr. Smithers 0 1
Johnathan Smithe 1 1
Setting #partialMatch to 0 will exclude "Mr. Smithers".

Related

MS SQL Server - replace names while avoiding words containing the names

This is my first time posting on Stack Overflow, so please let me know if I can do anything better or provide more information.
I have been working on this issue for a few days now. I have a table with comments from employees about the company. Some of them could refer to specific employees in the company. For HR reasons, we want to replace any occurrence of an employee name with the word 'employee'. We aren't accounting for typos or misspellings.
An example of my desired outcome would be:
Input: 'I dislike dijon mustard. My boss Jon sucks.'
Name to search for: 'Jon'
Output: 'I dislike dijon mustard. My boss employee sucks.'
Another example:
Input: 'Aggregating data is boring. Greg is the worst person ever.'
Name to search for: 'Greg'
Output: 'Aggregating data is boring. employee is the worst person ever.'
I want to search the comments for occurrences of the employee names, but only if they aren't followed by other letters or numbers on either end. Occurrences with spaces or punctuation on either end of the name should be replaced.
So far I have tried the suggestions in the following threads:
How to replace a specific word in a sentence without replacing in substring in SQL Server
replacing-in-substring-in-s
This yielded the following
update c
set c.Comment = rtrim(ltrim(Replace(replace(' ' + c.Comment + ' ',' ' + en.FirstName + ' ', 'employee'), ' ' + en.FirstName + ' ', 'employee')))
from AnswerComment c
join #EmployeeNames en on en.SurveyId = c.SurveyId
and c.Comment like '%' + en.FirstName + '%'
However, I got results like this:
Input: 'I hate bob.'
Name to search for: 'Bob'
Output: 'I hate bob.'
Input: 'Jon sucks'
Name to search for: 'Jon'
Output: 'employeesucks'
A coworker looked at this thread Replace whole word using ms sql server "replace"
and gave me the following based off of it:
DECLARE #token VARCHAR(10) = 'bob';
DECLARE #replaceToken VARCHAR(10) = 'employee';
DECLARE #paddedToken VARCHAR(10) = ' ' + #token + ' ';
DECLARE #paddedReplaceToken VARCHAR(10) = ' ' + #replaceToken + ' ';
;WITH Step1 AS (
SELECT CommentorId
, QuestionId
, Comment
, REPLACE(Comment, #paddedToken, #paddedReplaceToken) AS [Value]
FROM AnswerComment
WHERE SurveyId = 90492
AND Comment LIKE '%' + #token + '%'
), Step2 AS (
SELECT CommentorId
, QuestionId
, Comment
, REPLACE([Value], #paddedToken, #paddedReplaceToken) AS [Value]
FROM Step1
), Step3 AS (
SELECT CommentorId
, QuestionId
, Comment
, IIF(CHARINDEX(LTRIM(#paddedToken), [Value]) = 1, STUFF([Value], 1, LEN(TRIM(#paddedToken)), TRIM(#paddedReplaceToken)), [Value]) AS [Value]
FROM Step2
)
SELECT CommentorId
, QuestionId
, Comment
, IIF(CHARINDEX(REVERSE(RTRIM(#paddedToken)), REVERSE([Value])) = 1,
REVERSE(STUFF(REVERSE([Value]), CHARINDEX(REVERSE(RTRIM(#paddedToken)), REVERSE([Value])), LEN(RTRIM(#paddedToken)), REVERSE(RTRIM(#paddedReplaceToken)))),
[Value])
FROM Step3;
But I have no idea how I would implement this.
Another thread I can't find anymore suggested using %[^a-z0-9A-Z]% for searching, like this:
update c
set c.Comment = REPLACE(c.Comment, en.FirstName, 'employee')
from AnswerComment c
join #EmployeeNames en on en.SurveyId = c.SurveyId
and c.Comment like '%' + en.FirstName + '%'
and c.Comment not like '%[^a-z0-9A-Z]%' + en.FirstName + '%[^a-z0-9A-Z]%'
select ##ROWCOUNT [first names replaced]
This doesn't work for me. It replaces occurrences of the employee names even if they're part of a larger word, like in this example:
Input: 'I dislike dijon mustard.'
Name to search for: 'Jon'
Output: 'I dislike diemployee mustard.'
At this point it seems to me that it's impossible to accomplish this. Is there anything wrong with how I've implemented these, or anything obvious that I'm missing?
Here is a method that uses a combination of STUFF and PATINDEX.
It'll only replace the first occurence of the name in the comment.
So it might have to be executed more than once till nothing gets updated by it.
UPDATE c
SET c.Comment = STUFF(c.Comment, PATINDEX('%[^a-z0-9]'+en.FirstName+'[^a-z0-9]%', '/'+c.Comment+'/'), len(en.FirstName), 'employee')
FROM AnswerComment c
JOIN #EmployeeNames en ON en.SurveyId = c.SurveyId
WHERE '/'+c.Comment+'/' LIKE '%[^a-z0-9]'+en.FirstName+'[^a-z0-9]%';
Something like this seems to work.
declare #charsTable table (notallowed char(1))
insert into #charsTable (notallowed) values (',')
insert into #charsTable (notallowed) values ('.')
insert into #charsTable (notallowed) values (' ')
declare #input nvarchar(max) = 'Aggregating data is boring. Greg is the worst person ever.'
declare #name nvarchar(50) = 'Greg'
--declare #input nvarchar(max) = 'I dislike dijon mustard. You know who sucks? My boss Jon.'
--declare #name nvarchar(50) = 'Jon'
select case when #name + notallowed = value or notallowed + #name = value or notallowed + #name = value then replace(value, #name, 'employee') else value end 'data()' from string_split(#input, ' ')
left join #charsTable on #name + notallowed = value or notallowed + #name = value or notallowed + #name + notallowed = value
for xml path('')
Results:
Aggregating data is boring. employee is the worst person ever.
I dislike dijon mustard. You know who sucks? My boss employee.

Add character to selected duplicate value in SQL

I need to add character / number to selected duplicate values.
This is what I need:
SELECT Name -- Here I need to add for example 1 if It have duplicates
-- If It is hard way to code, how to add 1 to all selected values?
FROM Example
WHERE Id BETWEEN 25 AND 285
If there are 2 equal names Peter It should select Peter and second Peter1
If there is no easy way to make It, how to add 1 to all selected lines? Should select Peter1 instead of Peter
I've tried this:
SELECT Name + ' 1' AS Name -- in this case selecting wrong column
FROM Example
WHERE Id BETWEEN 25 AND 285
EDIT
SELECT #cols += ([Name]) + ','
FROM (SELECT Name --I neeed to integrate It here
FROM FormFields
WHERE ID BETWEEN 50 AND 82
) a
If I use this:
SELECT #cols += ([Name]) + ',' -- here throws error
FROM (SELECT Name + CASE WHEN RowNum = 1 THEN '' ELSE CONVERT(NVARCHAR(100), RowNum-1) END AS [UpdatedName]
FROM (
SELECT Name AS Name,
ROW_NUMBER() OVER (PARTITION BY Name ORDER BY Name) AS "RowNum"
FROM FormFields
WHERE Id Between 50 And 82) x
) a
It throws error: Invalid column name 'Name'.
EDIT 2
It's different tests but some of them have the same criteria. That's why I need It to rename.
You can do this via getting the Row_Number and using a Case. Here's an example for SQL Server:
;With Cte As
(
Select Name, Row_Number() Over (Partition By Name Order By Name) RN
From Example
Where Id Between 25 And 285
)
Select Case When RN = 1 Then Name Else Name + Cast((RN - 1) As Varchar (3)) End As Name
From Cte
You could use the ROW_NUMBER function built into SQL server.
select Name + case when RowNum = 1 then '' else CONVERT(varchar(100), RowNum-1) end as "UpdatedName"
from (
select name as "Name",
ROW_NUMBER() over (partition by name order by name) as "RowNum"
from Example
Where Id Between 25 And 285) x
Please note that this still doesn't guarantee you unique names. Afterall, someone could already have a name of "MyName1", so if you had 2 people with names "MyName" you'd still get 2 "MyName1" with this select statement.
This is very unusual request, it looks like you are trying to "make car run with wheels on the roof" :)
The root problem is almost sure wrong database design... Pivot is usually used for data summaries. If you have in the same column "Peter" and "Peter" with different meanings, it looks that there is something wrong. Or do you need to differentiate both Peters for any other reason?
I do not understand what are you trying to achieve. If Peter is always Peter, and you just want to avoid duplicities, you can simply use "group by Name". But this is what pivot does automatically... If Peter and Peter have two different meanings (like Peter1 and Peter2), you should think about changing database structure, if possible.
Or try to explain more deeply what are you trying to achieve.
EDIT:
OK, now I understand the desired output. And what is the structure of your source data table(s)? From your schema it is clear that you need to make PIVOT columns based on
Testname+groupId
or
Testname+convert(varchar(100),groupId)
if groupId is number. That is your Peter1,Peter2 composition. It will create columns that you need. But I dont't know where testname and groupId are located in your datatables. Do test names correspond to column NAMES or to VALUES stored in DB? Is groupId something like TestId? Again column or value? Provide more info about source data structure, if you need more help, your problem is not so complicated.
Since the columns have group IDs, concatenate the Column name with an Underscore and GroupID as a key value and when you display it, strip the underscore and trailing characters.
Like This:
SELECT #cols += ([Name]) + ','
FROM (SELECT Name + '_' + CAST(GroupId AS varchar)
FROM FormFields
WHERE ID BETWEEN 50 AND 82
) a
I assume you are using this to build a dynamic SQL statement. I'm not sure what the schema of your FormFields Table is, but if it includes something like the test name you could append an AS [Name] + ' - ' +[TestName] to have the column header be something more useful. I would say try a PIVOT, but that could get pretty ungainly if the tests don't have the majority of the fields in common...
I also assume you are storing responses to these prompts in a table that looks something like this:
CREATE TABLE [Responses]
(
RespID int IDENTITY NOT NULL,
UserID int NOT NULL,
FieldID int NOT NULL,
RespVal int/varchar/whatever NOT NULL
)
Then perhaps you have a [Test] table with some test metadata that acts as the primary key for your GroupID Foreign key in your FormFields table.
In your example you show responses across all columns, but I'm not sure how that would work since (unless I'm missing something in your explanation and the inferences I've made to your design) one set of responses would only be populated for one of the groups per row, unless you are aggregating responses, but then by what criteria? Perhaps the rows correspond to respondents and all respondents are required to answer across all form types. In that case, your output would work as a PIVOT like this:
DECLARE #sql varchar(4000) = ''
DECLARE #colList varchar(1000)
DECLARE #selList varchar(1000)
;WITH NameBase
AS
(
SELECT t.Name [TestName], f.Name [FieldName], f.GroupId
FROM [FormFields] f
INNER JOIN [Tests] t ON f.GroupID = t.ID
)
SELECT #colList = COALESCE(#colList + ',','') + QUOTENAME([FieldName] + '_' + [GroupId])
, #selList = COALESCE(#selList + ',','') + QUOTENAME([FieldName] + '_' + [GroupId]) + ' AS ' + QUOTENAME([FieldName] + ' - ' + [TestName])
FROM NameBase
SELECT #sql = 'SELECT [UserName],' + #selList + ' FROM (
SELECT u.Name [UserName], f.Name + '_' + f.GroupId [FieldName], r.RespVal [Response]
FROM Responses r
INNER JOIN [TestUsers] u ON r.UserID = u.ID
INNER JOIN [FormFields] f ON r.FieldID = f.ID) t
PIVOT (MAX([Response]) FOR [FieldName] IN (' + #colList + ')) pvt'
EXECUTE(#sql);
I haven't tested that yet, but it should at least point you in the right direction. I'll try to build a SqlFiddle to test it in a little bit.

a sql query with multiple search word

i use following query to get all data which contains the some words (which is split by a function) in the name column of the inventoryLocalization table.
in the example i have split "red green blue" string.
as it should be, it returned all rows like OR operator.
SELECT distinct
inL.name
FROM dbo.[inventoryLocalization] inL
JOIN fnSplitString (N'red green blue',' ' ) words ON (inL.name LIKE '%'+ words.item +'%')
My question is, is it possible to get rows which has all words, as in the AND operator.
select inL.name from dbo.[inventoryLocalization] inL
where not exists
(select 1 from fnSplitString(N'red green blue',' ') words
where (inL.name NOT LIKE '%'+ words.item +'%'))
Try something like this:
DECLARE #SomeWords NVARCHAR(200), #Num INT
SET #SomeWords = 'red green blue'
SELECT #Num = COUNT(*)
FROM fnSplitString (#SomeWords,' ')
SELECT inL.name
FROM dbo.[inventoryLocalization] inL
JOIN fnSplitString (#SomeWords,' ' )words
ON (inL.name LIKE '%'+ words.item +'%')
GROUP BY inL.name
HAVING COUNT(*) = #Num

Trouble combining rows into one column using CAST(

Ok SO, here's your time to shine!
No really, I'm getting my butt kicked by an MS-SQL query that I can't seem to get to work.
What I am trying to do is search on a patient name; but also return patients who have a similar first or last name to the querying patient's last name. So "John Smith" can return anyone named "John Smith" or anyone who has a first or last name like "smith". If the a patient has multiple disease states, then combine those disease states into a single column. I have the following tables (though of course there are many more columns, but these are the most imortant):
Patient Table
PatientID FirstName LastName UserIDFK
10000 John Smith 1
10001 Miss Smith 2
10002 Smith Bomb 3
10003 Bobby Smith 4
-- etc
DiseaseStateForUser
UserIDFK DiseaseStateRefId
1 1
1 2
2 2
3 1
3 2
4 1
GlobalLookUp
RefId Ref_Code
1 HIV
2 HEPC
The results I'm looking for are this:
PatientID FirstName LastName DiseaseStates
10000 John Smith HIV|HEPC
10001 Miss Smith HEPC
10002 Smith Bomb HIV|HEPC
10003 Bobby Smith HIV
I've taken the examples from these questions (and countless others):
Is there a way to create a SQL Server function to “join” multiple
rows from a subquery into a single delimited
field?
Simulating group_concat MySQL function in MS SQL Server
2005?
As well as from this blog post Emulating MySQL’s GROUP_CONCAT() Function in SQL Server 2005 I came up with the following SQL procedure
DECLARE
#PatientID INT=null,
#FirstName Varchar(15)= null,
#LastName Varchar(15)= 'Smith',
#Name Varchar(15) = 'John Smith',
Select
Patient.First_Name,
Patient.Last_Name,
patient.PatientID,
(select CAST(GlobalLookUp.Ref_Code + '|' as VARCHAR(MAX))
from
TBL_PATIENT patient
,TBL_GBLLOOKUP GlobalLookUp
,TBL_DiseaseStateForUser DiseaseStateForUser
-- Try and make a collection of all the PatientIDs
-- that match the search criteria
-- so that only these are used to build
-- the DiseaseStatesColumn
,(Select
Patient.PatientID
FROM TBL_PATIENT patient
,TBL_SITEMASTER SiteMaster
,TBL_USERMASTER UserMaster
,TBL_USERSINSITES UserInSites
,TBL_GBLLOOKUP GlobalLookUp
,TBL_DiseaseStateForUser DiseaseStateForUser
WHERE (((patient.[Last_Name] like #LastName + '%') OR (patient.[Last_Name] Like #Name + '%' ))
OR ((patient.[First_Name] Like #Name + '%' ))
OR (patient.[First_Name] + ' ' + patient.[Last_Name] Like #Name + '%' ))
AND UserMaster.User_Id = UserInSites.User_Id_FK
AND UserInSites.Site_Id_FK = SiteMaster.Site_Id
AND UserInSites.Is_Active = 'True'
AND patient.[User_Id_FK] = UserMaster.[User_Id]
AND (DiseaseStateForUser.User_Id_FK = patient.User_Id_FK
AND DiseaseStateForUser.DiseaseState_RefId_FK = GlobalLookUp.Ref_Id)
and DiseaseStateForUser.Is_Active='True'
AND patient.[Is_Active] = 'TRUE'
group by Patient.PatientID) as PATIENTIDs
where patient.PatientID = PATIENTIDs.PatientID
AND (DiseaseStateForUser.User_Id_FK = patient.User_Id_FK
AND DiseaseStateForUser.DiseaseState_RefId_FK = GlobalLookUp.Ref_Id)
For XML PATH('')) as MultiDiseaseState
FROM TBL_PATIENT patient, TBL_SITEMASTER SiteMaster ,TBL_USERMASTER UserMaster,TBL_USERSINSITES UserInSites, TBL_GBLLOOKUP GlobalLookUp, TBL_DiseaseStateForUser DiseaseStateForUser
WHERE (((patient.[Last_Name] like #LastName + '%') OR (patient.[Last_Name] Like #Name + '%' ))
or ((patient.[First_Name] Like #Name + '%' ))
OR (patient.[First_Name] + ' ' + patient.[Last_Name] Like #Name + '%' ))
AND patient.PatientID = patient.PatientID
AND UserMaster.User_Id = UserInSites.User_Id_FK
AND UserInSites.Site_Id_FK = SiteMaster.Site_Id
AND UserInSites.Is_Active = 'True'
AND patient.[User_Id_FK] = UserMaster.[User_Id]
AND DiseaseStateForUser.User_Id_FK = patient.User_Id_FK
AND DiseaseStateForUser.DiseaseState_RefId_FK = GlobalLookUp.Ref_Id
and DiseaseStateForUser.Is_Active='True'
AND patient.[Is_Active] = 'TRUE'
group by PatientID, patient.First_Name, patient.Last_Name, GlobalLookUp.Ref_Code
order by PatientID
Unfortunately, this query nets me the following:
PatientID FirstName LastName MultiDiseaseState
10000 John Smith HIV|HEPC|HEPC|HIV|HEPC|HIV
10001 Miss Smith HIV|HEPC|HEPC|HIV|HEPC|HIV
10002 Smith Bomb HIV|HEPC|HEPC|HIV|HEPC|HIV
10003 Bobby Smith HIV|HEPC|HEPC|HIV|HEPC|HIV
In other words, the select CAST(GlobalLookUp.Ref_Code + '|' as VARCHAR(MAX)) call is building up the MultiDiseaseState column with all of the disease states for ALL of the selected patients.
I know there is something fundamentally wrong with the most inner SELECT statement, but I'm having a hard time figuring out what it is and how to write the query so that it builds only the disease states for a given patient.
Kind of a long post, but are there any suggestions people can make given the code snippets I've provided?
You should be able to use the Stuff function (I think it's only on SQL 2005 and higher) to make this work, I took your example data and wrote a demonstration off of that
SET NOCOUNT ON
CREATE TABLE #Patient
(
PatientID INT,
FirstName varchar(25),
LastName varchar(25),
UserIDFK INT
)
INSERT INTO #PATIENT SELECT 10000,'John','Smith',1
INSERT INTO #PATIENT SELECT 10001,'Miss','Smith',2
INSERT INTO #PATIENT SELECT 10002,'Smith','Bomb',3
INSERT INTO #PATIENT SELECT 10003,'Bobby','Smith',4
CREATE TABLE #DiseaseStateForUser
(
UserIDFK int,
DiseaseStateRefId int
)
INSERT INTO #DiseaseStateForUser SELECT 1,1
INSERT INTO #DiseaseStateForUser SELECT 1,2
INSERT INTO #DiseaseStateForUser SELECT 2,2
INSERT INTO #DiseaseStateForUser SELECT 3,1
INSERT INTO #DiseaseStateForUser SELECT 3,2
INSERT INTO #DiseaseStateForUser SELECT 4,1
CREATE TABLE #GlobalLookUp
(
RefId int,
Ref_Code varchar(10)
)
INSERT INTO #GlobalLookUp SELECT 1,'HIV'
INSERT INTO #GlobalLookUp SELECT 2,'HEPC'
SELECT
PatientID,
UserIDFK,
FirstName,
LastName,
STUFF(
(SELECT '|' + l.Ref_Code
FROM #DiseaseStateForUser u with (Nolock)
JOIN dbo.#GlobalLookUp l with (nolock)
ON u.DiseaseStateRefId = l.RefId
WHERE u.UserIDFK = p.UserIDFK FOR XML PATH('')
)
, 1, 1, '')
FROM #PATIENT p with (Nolock)
GROUP BY PatientID, FirstName, LastName, UserIDFK

Combination of 'LIKE' and 'IN' using t-sql

How can I do this kind of selection:
SELECT *
FROM Street
WHERE StreetName LIKE IN ('% Main Street', 'foo %')
Please don't tell me that I can use OR because these actually comes from a query.
There is no combined LIKE and IN syntax but you can use LIKE to JOIN onto your query as below.
;WITH Query(Result) As
(
SELECT '% Main Street' UNION ALL
SELECT 'foo %'
)
SELECT DISTINCT s.*
FROM Street s
JOIN Query q ON StreetName LIKE q.Result
Or to use your example in the comments
SELECT DISTINCT s.*
FROM Street s
JOIN CarStreets cs ON s.StreetName LIKE cs.name + '%'
WHERE cs.Streets = 'offroad'
You don't have a lot of choices here.
SELECT * FROM Street Where StreetName LIKE '% Main Street' OR StreetName LIKE 'foo %'
If this is part of an existing, more complicated query (which is the impression I'm getting), you could create a table value function that does the checking for you.
SELECT * FROM Street Where StreetName IN (dbo.FindStreetNameFunction('% Main Street|foo %'))
I'd recommend using the simplest solution (the first). If this is nested inside a larger, more complicated query, post it and we'll take a look.
I had a similar conundrum but due to only needing to match the start of a string, I changed my 'like' to SUBSTRING as such:
SELECT *
FROM codes
WHERE SUBSTRING(code, 1, 12) IN ('012316963429', '012315667849')
You can resort to Dynamic SQL and wrapping up all in a stored procedure.
If you get the LIKE IN param in a string as tokens with a certain separator, like
'% Main Street,foo %,Another%Street'
first you need to create a function that receives a list of LIKE "tokens" and returns a table of them.
CREATE FUNCTION [dbo].[SplitList]
(
#list nvarchar(MAX),
#delim nvarchar(5)
)
RETURNS #splitTable table
(
value nvarchar(50)
)
AS BEGIN
While (Charindex(#delim, #list)>0) Begin
Insert Into #splitTable (value)
Select ltrim(rtrim(Substring(#list, 1, Charindex(#delim, #list)-1)))
Set #list = Substring(#list, Charindex(#delim, #list)+len(#delim), len(#list))
End
Insert Into #splitTable (value) Select ltrim(rtrim(#list))
Return
END
Then in the SP you have the following code
declare
#sql nvarchar(MAX),
#subWhere nvarchar(MAX)
#params nvarchar(MAX)
-- prepare the where sub-clause to cover LIKE IN (...)
-- it will actually generate where sub clause StreetName Like option1 or StreetName Like option2 or ...
set #subWhere = STUFF(
(
--(**)
SELECT ' OR StreetName like ''' + value + '''' FROM SplitList('% Main Street,foo %,Another%Street', ',')
FOR XML PATH('')
), 1, 4, '')
-- create the dynamic SQL
set #sql ='select * from [Street]
where
(' + #subWhere + ')
-- and any additional query params here, if needed, like
AND StreetMinHouseNumber = #minHouseNumber
AND StreetNumberOfHouses between (#minNumberOfHouses and #maxNumberOfHouses)'
set #params = ' #minHouseNumber nvarchar(5),
#minNumberOfHouses int,
#minNumberOfHouses int'
EXECUTE sp_executesql #sql, #params,
#minHouseNumber,
#minNumberOfHouses,
#minNumberOfHouses
Of course, if you have your LIKE IN parameters in another table or you gather it through a query, you can replace that in line (**)
I believe I can clarify what he is looking for, but I don't know the answer. I'll use my situation to demonstrate. I have a table with a column called "Query" that holds SQL queries. These queries sometimes contain table names from one of my databases. I need to find all Query rows that contain table names from a particular database. So, I can use the following code to get the table names:
SELECT TABLE_NAME FROM INFORMATION_SCHEMA.TABLES
I'm trying to use a WHERE IN clause to identify the Query rows that contain the table names I'm interested in:
SELECT *
FROM [DatasourceQuery]
WHERE Query IN LIKE
(
SELECT TABLE_NAME FROM INFORMATION_SCHEMA.TABLES
)
I believe the OP is trying to do something like that.
This is my way:
First create a table function:
create function [splitDelimeter](#str nvarchar(max), #delimeter nvarchar(10)='*')
returns #r table(val nvarchar(max))
as
begin
declare #x nvarchar(max)=#str
set #x='<m>'+replace(#x, #delimeter, '</m><m>')+'</m>'
declare #xx xml=cast(#x as xml)
insert #r(val)
SELECT Tbl.Col.value('.', 'nvarchar(max)') id
FROM #xx.nodes('/m') Tbl(Col)
return
end
Then split the search text with your preference delimeter. After that you can do your select with left join as below:
declare #s nvarchar(max)='% Main Street*foo %'
select a.* from street a
left join gen.splitDelimeter(#s, '*') b
on a.streetname like b.val
where val is not null
What I did when solving a similar problem was:
SELECT DISTINCT S.*
FROM Street AS S
JOIN (SELECT value FROM String_Split('% Main Street,foo %', N',')) T
ON S.StreetName LIKE T.value;
Which is functionally similar to Martin's answer but a more direct answer to the question.
Note: DISTINCT is used because you might get multiple matches for a single row.