Using the SQL LIKE operator with %% - sql-server

I had a requirement to create a query in SQL Server where the search condition would include/exclude a table based on user input.
Say I have two tables, TABLE_A and TABLE_B with columns KEYCOLUMN_A and COLUMN_A in TABLE_A and columns FKCOLUMN_B and COLUMN_B in TABLE_B.
And a query like:
SELECT TABLE_A.* FROM TABLE_A, TABLE_B WHERE TABLE_A.KEYCOLUMN_A = TABLE_B.FKCOLUMN_B
AND TABLE_A.COLUMN_A LIKE '%SEARCH%' AND TABLE_B.COLUMN_B LIKE '%SEARCH2%'
Now if the user does not input SEARCH2, I don't need to search TABLE_B. But this would mean an IF ELSE clause. And as the number of "optional" tables in the query increases, the permutations and combinations would also increase and there will be many IF and ELSE statements.
Instead I decided to keep the statement as it is. So if SEARCH2 is empty, the query will effectively become:
SELECT * FROM TABLE_A, TABLE_B WHERE TABLE_A.KEYCOLUMN_A = TABLE_B.FKCOLUMN_B
AND TABLE_A.COLUMN_A LIKE '%SEARCH%' AND TABLE_B.COLUMN_B LIKE '% %'
Can the SQL optimizer recognize that LIKE %% is as good as removing the condition itself?

Wrap an OR around your "B" table, such as:
AND (len(searchString)=0 OR table_b.column_b LIKE "%searchString%" )
This way, if no value for the string, its length would be zero, and the first part of the OR would be evaluated, always come back as true and return that portion of the equation as valid and ignore the other half using the LIKE clause.
You could apply the same for as many linked tables as you need.

First thing, you have a space in your example:
AND TABLE_B.COLUMN_B LIKE '% %'
That will never be optimized as it is indeed a significant condition.
Now, I think that if it is optimized away depends on the database engine and how smart it is.
For example, SQL Server 2005 does offer the same execution plan for the two types of queries, while MySQL 5.0.38 does not.

LIKE is used with the WHERE clause to search, update, and delete a record using wild cards.
Example:
To search all records whose employee name is starred from a character, 'a':
select * from Employee where Name like 'a%'
To update all records with name amit whose employee name is starting with a character, 'a':
update Employee set Name='amit' where Name like 'a%'
To delete all records whose employee name is starting with a character, 'a':
delete from Employee where Name like 'a%'

The LIKE operator is used in a WHERE clause to search for a specified pattern in a column
LIKE '%[p-s]' -- "It search data from table parameter where sentence ending with p,q,r,s word."
LIKE '[0-9]' --It use for search only numeric value
LIKE '%table%' -- it use for search parameter from table where use "table" keyword'.
LIKE %[^p-r] -- it set the condition where Not Ending With a Range of Characters
Example:
SELECT T1.BrandName,T1.BrandID,T2.CategoryName,T2.Color FROM TABLE1 T1
LEFT JOIN TABLE2 T2 on T1.ID = T2.BrandID
WHERE T1.BrandName LIKE '%Samsung%'
Example:
SELECT T1.BrandName,T1.BrandID,T2.CategoryName,T2.Color FROM TABLE1 T1
LEFT JOIN TABLE2 T2 on T1.ID = T2.BrandID
WHERE T1.BrandName LIKE '%[a-j]'

In MySQL you can also use ILIKE, and then it's case insensitive.

You can rewrite you query like this:
SELECT TABLE_A.* FROM TABLE_A, TABLE_B WHERE TABLE_A.KEYCOLUMN_A = TABLE_B.FKCOLUMN_B
AND (#paramA='' or TABLE_A.COLUMN_A LIKE '%' + #paramA + '%')
AND (#paramB='' or TABLE_B.COLUMN_B LIKE '%' + #paramB + '%')
This way, if paramA or paramB is '', then the other column that is queried inside same parentheses will not be queried.

Use UNION and proper JOINs.
The %foo% search term is bad enough (can't use index) without adding OR and LEN to the mix too.
SELECT
TABLE_A.*
FROM
TABLE_A
JOIN
TABLE_B On TABLE_A.KEYCOLUMN_A = TABLE_B.FKCOLUMN_B
WHERE
TABLE_A.COLUMN_A LIKE '%SEARCH%' AND TABLE_B.COLUMN_B LIKE '%SEARCH2%'
UNION
SELECT
TABLE_A.*
FROM
TABLE_A
WHERE
TABLE_A.COLUMN_A LIKE '%SEARCH%'

Related

Comparing 2 tables in SQL Server

I have 2 SQL tables, one contains 2 columns, First Name and Last Name and the other has a column called NAME which has full names in it. I am trying to find if any of the values from the Last Name column in table1 can be found in the NAME column of table2. So far I have tried the following query without much success:
SELECT * FROM table1
CROSS APPLY
(SELECT * FROM table2 WHERE ('%'+table1.[Last Name]+'%' LIKE table2.NAME)) table2
I am not sure, but I think this works:
SELECT *
FROM table1
WHERE ISNULL((SELECT TOP(1) 1 FROM tabl2 WHERE Name LIKE '%' + table1.LastName + '%'), 0)= 1
This query's accuracy can suffer in case of similar first and last names. You can add white spaces for better accuracy: LIKE '% table1.LastName %'.

SQL Query in which the WHERE clause uses LIKE on all data from a column in another table

Azure SQL Server 2017:
We have a table called dbo.keywords with one column, called keywords. This column consists of ~10,000 varchar(50) entries.
We have another table called dbo.articles. Both tables are in the same database.
The query we are trying to create would be such:
SELECT * FROM dbo.articles
WHERE TextValue LIKE
(**any of the 10,000 values of the keywords column in the dbo.keywords table**).
The part in the parentheses above is the part that I am unclear on accomplishing. If not for the LIKE part, I suppose I could use a SELECT subquery, but the LIKE piece is what's throwing me.
I suspect that this will be the more "perfomant" option (I use quotes, as using LIKE with a leading wildcard will make the query non-SARGable):
SELECT *
FROM dbo.articles a
WHERE EXISTS (SELECT 1
FROM dbo.keywords k
WHERE a.TextValue LIKE '%' + k.keyword + '%');
This will avoid duplicate rows, and a costly DISTINCT; as I suspect that TextValue could have some lengthy values.
You can achieve it by using JOIN with LIKE.
Could you please try the query below:
SELECT *
FROM dbo.articles [AR]
INNER JOIN dbo.keywords [KW] ON [AR].TextValue LIKE '%' + [KW].keywords + '%';
You'll want to join the tables, and use the LIKE clause in the join condition:
SELECT DISTINCT a.* FROM dbo.articles a
JOIN dbo.keywords k ON a.TextValue LIKE '%' + k.keywords + '%';

T-SQL pattern matching with exceptions

Here's a problem I've repeatedly encountered while playing with the Stack Exchange Data Explorer, which is based on T-SQL:
How to search for a string except when it occurs as a substring of some other string?
For example, how can I select all records in a table MyTable where the column MyCol contains the string foo, but ignoring any foos that are part of the string foobar?
A quick and dirty attempt would be something like:
SELECT *
FROM MyTable
WHERE MyCol LIKE '%foo%'
AND MyCol NOT LIKE '%foobar%'
but obviously this will fail to match e.g. MyCol = 'not all foos are foobars', which I do want to match.
One solution I've come up with is to replace all occurrences of foobar with some dummy marker (that is not a substring of foo) and then checking for any remaining foos, as in:
SELECT *
FROM MyTable
WHERE REPLACE(MyCol, 'foobar', 'X') LIKE '%foo%'
This works, but I suspect it's not very efficient, since it has to run the REPLACE() on every record in the table. (For SEDE, this would typically be the Posts table, which currently has about 30 million rows.) Are the any better ways to do this?
(FWIW, the real use case that prompted this question was searching for SO posts with image URLs that use the http:// scheme prefix but do not point to the host i.stack.imgur.com.)
Neither of the ways given so far are guaranteed to work as advertised and only perform the REPLACE on a subset of rows.
SQL Server does not guarantee short circuiting of predicates and can move compute scalars up into the underlying query for derived tables and CTEs.
The only thing that is (mostly) guaranteed to work is the CASE statement. Below I use the syntactic sugar variety of IIF that expands out to CASE
SELECT *
FROM MyTable
WHERE 1 = IIF(MyCol LIKE '%foo%',
IIF(REPLACE(MyCol, 'foobar', 'X') LIKE '%foo%', 1, 0),
0);
A three-stage filter should work:
collect all rows matching '%foo%';
replace all instances of 'foobar' with a non-occurring string (such as '' perhaps);
Check again for matching '%foo%'
Here you only perform the REPLACE on potentially matching rows, not all rows. If you are expecting only a small percentage of matches, this should be much more efficient.
SQL would look like this:
;with data as (
select *
from MyTable
where MyCol like '%foo%'
)
select *
from data
where replace(MyCol, 'foobar', 'X') like '%foo%'
Note that a sub-query is required, as there are no expression short-cuts in SQL; the engine is free to reorder Boolean terms as desired for efficient processing within a singe query level.
This will be faster than your current query:
SELECT *
FROM MyTable
WHERE
MyCol like '%foo%' AND
REPLACE(MyCol, 'foobar', 'X') LIKE '%foo%'
The REPLACE is calculated after MyCol has been applied, so this is faster than just:
REPLACE(MyCol, 'foobar', 'X') LIKE '%foo%'
Assuming you're only interested in finding instances of foo with spaces surrounding them
SELECT *
FROM MyTable
WHERE MyCol LIKE 'foo %' OR MyCol LIKE '% foo %' OR MyCol LIKE '% foo'

SQL Server : make a select and test every occurrence/row inside another select

I have a SQL Server stored procedure that receives a comma separated string as parameter.
I also have a table-valued function that takes this parameter, splits it (between the commas) and returns as a 'table'.
This procedures is a 'search procedure' that uses LIKE operator to find matching terms.
How can I loop through this parameter that has been transformed into a table and compare it with LIKE?
The sequence that I'd need is something like this:
SQL Server procedure has been called and a separated comma string has been passed as parameter.
A table-valued function gets called to strip this string and transform it in a result table. (It´s not a real table, its just the results). Until here I have already done, the next part is the one I need help:
Loop through this recently created 'table' and search in a specific column of another table.
eg.
SELECT *
FROM tbl_names
WHERE col_names LIKE '%' + (the search term here) + '%'
You can join your table on result of your function:
select * from SomeTable st
join dbo.SomeFunction(#str) sf on st.SomeColumn like '%' + sf.Term +'%'
To order by occurences do something like this:
select * from SomeTable st
join(
select st.ID, count(*) as Occurence from SomeTable st
join dbo.SomeFunction(#str) sf on st.SomeColumn like '%' + sf.Term +'%'
group by st.ID) ot on st.ID = ot.ID
order by ot.Occurence desc
I'd probably use a cross or outer apply with patindex if you want to know how many items matched
select S.*, m.matches
from sometable s
cross apply (select count(1) as matches from finction where patindex ('%' + function.Column + '%', s.coltosearch) > 1) as matched
Use cross apply if you only want to return rows that have matches and outer if you want all rows with a count of terms.
Note: Code example is untested

sql server 2005 - select records from tbl A contained WITHIN a text field of tbl B

I'm trying to work out a SQL Select in MS SQL 2005, to do the following:
TABLE_A contains a list of keywords... asparagus, beetroot, beans, egg plant etc (x200).
TABLE_B contains a record with some long free text (approx 4000 chars)...
I know what record within TABLE_B I am selecting (byID).
However I need to get a shortlist of records from TABLE_A that are contained WITHIN the text of the record in TABLE_B.
I'm wondering if SQLs CONTAINS function is uselful... but maybe not.
This needs to be a super quick query.
Cheers
It will never be super quick because of the LIKE and wildcard at each end. You can not index it and there are no whizzy tricks. However, because you have already filtered TableB then it should be acceptable. If you had a million rows in tableB, you could go for coffee while it ran
SELECT
A.KeyWordColumn
FROM
TableA A
JOIN
TableB B ON B.BigTextColumn LIKE '%' + A.KeyWordColumn+ '%'
WHERE
B.ByID = #ID --or constant etc
CONTAINS can be used if you have full text indexing: but not for a normal SQL query
I would try this
select keyword from table_a, table_b
where table_b.text like '%' + keyword + '%'
and table_b.Id = '111'

Resources