How to retrieve the matched word Text Search - sql

How to retrieve the word text search rows. For example, if I search input as 'water Bottel', I need an output like 'Water Soap Bottel','Water Milk Bottel','Water Copper Bottel'. I know how to use LIKE Operator.
IF OBJECT_ID('tempdb..#SearchText') IS NOT NULL
DROP TABLE #SearchText
CREATE TABLE #SearchText
(
ProductId INT,
ProductName VARCHAR(500)
)
INSERT INTO #SearchText VALUES
(1,'Water Soap Bottel'),
(2,'Water Milk Bottel'),
(3,'Wooden Box'),
(4,'Water Plastic Bottel'),
(5,'Water Copper Bottel')

You can do this:
DECLARE #SearchTerm VARCHAR(100) = 'water bottel'
SELECT *
FROM #SearchText
WHERE ProductName LIKE '%' + REPLACE(#SearchTerm, ' ', '%') + '%'
However if you need to also return a row containing the phrase bottel water, the order of those words will mean the above doesn't work. In that case you will need to break up the query into multiple words, for example:
SELECT *
FROM #SearchText
WHERE ProductName LIKE '%water%'
AND ProductName LIKE '%bottel%'
If you have a full text index on that table, you could use CONTAINS:
SELECT *
FROM #SearchText
WHERE CONTAINS(ProductName, '"water" AND "bottel"')

You can split data on space and search if the splitted word match the splitted productname :
If all searched word must matches :
SELECT *
FROM #SearchText st
WHERE ( SELECT COUNT(value)
FROM STRING_SPLIT('water Bottel', ' ') ) = ( SELECT COUNT(*)
FROM STRING_SPLIT(st.ProductName, ' ') AS sv
JOIN STRING_SPLIT('water Bottel', ' ') AS ss
ON sv.value = ss.value )
If one or more word must match:
SELECT *
FROM #SearchText st
WHERE EXISTS ( SELECT 1
FROM STRING_SPLIT(st.ProductName, ' ') AS sv
JOIN STRING_SPLIT('water Bottel', ' ') AS ss
ON sv.value = ss.value )
Note : The string_split function is built-in on SQL Server 2016, you can search a create a custom implementation if you use a lower version.

Use LIKE operator.
SELECT
*
FROM #SearchText
WHERE LOWER(ProductName) LIKE '%water%'
AND LOWER(ProductName) LIKE '%bottel%'
You can ommit LOWER(...) function if collaction of column/database/server is case insensitive.

Related

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

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".

MSSQL query search with keyword list

I got one table that contains all information about products. I need to list all articles with a matching keywords (in this case the brand name) in a specific column. Is it possible to initiate some kind of a 'list' with all brand names that I can use for this operation? chaning OR for all brands seems kinda bad.
In the second step I only need to see all articles that does not contain a specific word order before they keywords from the first step.
DECLARE #brand NVARCHAR =
'bmw, toyota, mercedes'
SELECT [Artikelnum]
FROM [dbo].[LAGER]
WHERE [XWebtexke] like '%' + #brand +'%' AND [XWebtexke] NOT LIKE '%suited for%'
GO
Thats what I got so far, but it does not work in the way I need it.
DECLARE #brand NVARCHAR =
'bmw, toyota, mercedes'
select * from (
SELECT [Artikelnum]
FROM [dbo].[LAGER]
WHERE [XWebtexke] NOT LIKE '%suited for%' )t4
WHERE [XWebtexke] like '%' + #brand +'%'
GO
DECLARE #brand NVARCHAR =
'bmw, toyota, mercedes'
select * from (
SELECT [Artikelnum]
FROM [dbo].[LAGER]
WHERE [XWebtexke] NOT LIKE '%suited for%' )t4
WHERE t4.[XWebtexke] like '%' + #brand +'%'
GO
Realized you need all the keywords to match. Here is the solution for that.
You need to split the brand variable, try this:
DECLARE #brand NVARCHAR(200) = 'bmw, toyota, mercedes'
;WITH CTE as
(
SELECT '%'+ t.c.value('.', 'VARCHAR(2000)')+'%' val
FROM (
SELECT x = CAST('<t>' +
REPLACE(#brand, ', ', '</t><t>') + '</t>' AS XML)
) a
CROSS APPLY x.nodes('/t') t(c)
)
SELECT [Artikelnum]
FROM [dbo].[LAGER]
WHERE
not exists(SELECT * FROM CTE WHERE [XWebtexke] not like val)
and [XWebtexke] NOT LIKE '%suited for%'
I am assuming there is always a space after the comma, you can adjust the code with ease if that is not always the case.
In sqlserver 2016 you can use STRING_SPLIT instead of the split used in my answer

How to create Dynamic SQL based on two tables

I'm trying to construct a dynamic SQL based on the Cartesian product of two tables
Table1 Colunm1 Dev Test
table2 Column2 ProductNumber ProductDesc
here the result that I want:
(ProductNumber LIKE '%dev%' OR ProductDesc LIKE '%dev%' )
AND (ProductNumber LIKE '%Test%' OR ProductDesc LIKE '%Test%')
I tried to do some simple query like below but I cannot manage to add a AND instaed a OR between each column1 value
SELECT #sql = COALESCE(#sql + Colunm2 + ' LIKE ''%' + Colunm1 + '%'' OR ','')
from Table1, Table2
that give:
ProductNumber LIKE '%dev%' OR
ProductDesc LIKE '%dev%' OR
ProductNumber LIKE '%Test%' OR
ProductDesc LIKE '%Test%'
I can do it with a while but if you have a better solution I can use it
I note that you want your ORs grouped by table1.column1, so the below should work:
SELECT CASE WHEN row_num = 1 THEN ') AND (' ELSE '' END || code as code
FROM (
SELECT Column1, ROW_NUMBER() OVER (GROUP BY Column 1) as row_num, COALESCE( Column2 + ' LIKE ''%' + Column1 + '%'' OR ','') as code
FROM Table1, Table2
) gen_code
ORDER BY Column1, row_num
(I haven't tested it, but I have written lots of such code before)
It adds an additional ') AND (' at the beginning, but you can get it away if you use another ROW_NUMBER over the whole thing. It also lacks a closing ')', but you get the idea. Other than that, use your current approach with a variant of above code. Note that I assumed you have no string aggregation function available.

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

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.