MySQL question about "reverse LIKEs" - sql

Well given I have a value I want to check for potential matches in a database (in one varchar field) so I write something like:
SELECT * FROM table WHERE column LIKE "%value%"
Which will work if the value is something like "test" and the column has a value of "this is a test" however if it is reversed then I will not get a match I have tried things along the lines of:
SELECT * FROM table WHERE CONCAT("%",column,"%") LIKE "value"
but don't know exactly how to phrase this to Google to get a response I need, please help!

You can reverse a like statement. Just using the same syntax as a regular like query:
select
*
from
table
where
'value' like concat('%', column, '%')
Of course, if you felt wild and crazy, you could also use instr:
select * from table where instr('value', column) > 0
I don't know which one is faster, since I don't have a MySQL instance to test against, but it's worth trying both to see which wins.

SELECT *
FROM table
WHERE 'value' LIKE CONCAT('%', column, '%')

Related

Why do CONTAINS and LIKE return different results?

I have the following query. There are two possible columns that may hold the value I'm looking for, let's call them FieldA and FieldB.
If I execute this:
SELECT COUNT(1)
FROM Table
WHERE CONTAINS(Table.*, 'string')
I get back "0".
However, if I execute this:
SELECT COUNT(1)
FROM TABLE
WHERE FieldA LIKE '%string%' OR FieldB LIKE '%string%'
I get back something like 9000. I then checked and there are rows that have the word string in either FieldA.
Why does this happen? I recall that CONTAINS uses a full-text index, but I also recall that LIKE does the same, so if the problem was that the indexes are outdated, then it should fail for both of them, right?
Thanks
I believe that CONTAINS and full text searching will only yield whole word results, so you won't match the same as LIKE '%string%'. If you want to right wildcard your CONTAINS, you must write it like:
SELECT COUNT(1) FROM Table WHERE CONTAINS(Table.*, '"string*"')
However, if you want to left wildcard, you can't! You have to store a copy of your database reversed and then do:
SELECT COUNT(1) FROM Table WHERE CONTAINS(Table.*, '"gnirts*"')
https://learn.microsoft.com/en-us/previous-versions/office/developer/sharepoint-2010/ms552152(v=office.14)
How do you get leading wildcard full-text searches to work in SQL Server?
So in the example in the question, doing a CONTAINS(Table.*, 'string') is not the same as doing LIKE '%string%' and would not have the same results.

Sequence restrictions of SELECT statement

In my table I have a column of type nVarchar or nText
Suppose value of a this col is like this '... xxx yyy zzz ...'
I use SELECT to search table with this column
SELECT * FROM tbl_name WHERE col_name like '%xxx yyy%'
Since the I can't force users to enter words with my sequence I want to give same result with this query too:
SELECT * FROM tbl_name WHERE col_name like '%yyy xxx%'
It looks to me like you might want to consider normalizing your table. Specifically, if "yyy xxx" is the same as "xxx yyy", you're storing an array (or list or whatever you want to call it) in one column, which breaks first normal form. Normalize it so that each of those atoms (i.e. "xxx", "yyy") are stored separately and are related back to your original record. Then it's almost trivial to do the kind of thing you're looking to do.
You have to tokenize the user input into separate words inside your application code (not in sql) and then construct queries like
SELECT * FROM tbl_name WHERE
(col_name like '%yyy%') AND (col_name like '%xxx%') AND ...
Your best bet is to use both criteria, and "OR".
SELECT *
FROM tbl_name
WHERE (col_name like '%xxx yyy%')
OR (col_name like '%yyy xxx%');

How does phpmyadmin implement "search" feature?

In phpMyAdmin, there is a search in database feature by which I can input a word and find it in any table(s).
How to implement it by SQL statement? I know the LIKE operation, but it's syntax is:
WHERE column_name LIKE pattern
How to search in all columns? Any how to specify it's a exact keyword or regular express?
SELECT * FROM your_table_name WHERE your_column_name LIKE 'search_box_text';
Where search_box_text is what you enter in the search. It will also say in the result page what kind of query it made. The same query with regular expressions is:
SELECT * FROM your_table_name WHERE your_column_name REGEXP 'search_box_text';
Remember that the wildcard in mysql is %. Eg. "LIKE '%partial_search_text%'
If you want to search in multiple columns, you can check which columns are in table with:
DESCRIBE TABLE your_table_name;
Or if you already know your columns:
SELECT * FROM your_table_name
WHERE your_column_1 LIKE '%search%'
AND your_column_2 LIKE '%search%'
AND your_column_3 LIKE '%search%';

Is there another style for writing LIKE queries?

I write some queries like this:
SELECT *
FROM Sample.dbo.Temp
WHERE
Name LIKE '%ab%'
OR Name LIKE '%fg%'
OR NAME LIKE '%asd%'
OR ...
OR ...
OR Name LIKE '%kj%'
Is there anyway I can rewrite this query like this:
SELECT *
FROM Sample.dbo.Temp
WHERE
Name LIKE (
'%ab%'
OR '%fg%'
OR '%asd%'
OR ...
OR ...
OR '%kj%'
)
Just looks more comfortable both from a readability point of view and manageability. If the column Name changes, I can always make one change instead of a hundred (or using Find and Replace). Any suggestions?
No, you have to keep repeating the LIKE
Although you could probably fool around a bit to make it work something like that, it won't be prettier or more readable.
Perhaps you should generate the query programmatically instead of manually writing this?
PS: perhaps a fulltext index is a better idea here?
You can put the values in a table, perhaps a CTE, and semijoin to your table e.g.
WITH params
AS
(
SELECT *
FROM (
VALUES ('at'),
('fg'),
('asd'),
('kj')
) AS T (param)
)
SELECT *
FROM Sample.dbo.Temp T
WHERE EXISTS (
SELECT *
FROM params P
WHERE T.Name LIKE '%' + P.param + '%'
);
That looks long winded but if the CTE was instead a base table them the query could be data-driven i.e. if the list of parameter values need to change in the future then it would involve merely updating a table rather than amending hard-coded values (possibly in multiple objects).

How to implement a Keyword Search in MySQL?

I am new to SQL programming.
I have a table job where the fields are id, position, category, location, salary range, description, refno.
I want to implement a keyword search from the front end. The keyword can reside in any of the fields of the above table.
This is the query I have tried but it consist of so many duplicate rows:
SELECT
a.*,
b.catname
FROM
job a,
category b
WHERE
a.catid = b.catid AND
a.jobsalrange = '15001-20000' AND
a.jobloc = 'Berkshire' AND
a.jobpos LIKE '%sales%' OR
a.jobloc LIKE '%sales%' OR
a.jobsal LIKE '%sales%' OR
a.jobref LIKE '%sales%' OR
a.jobemail LIKE '%sales%' OR
a.jobsalrange LIKE '%sales%' OR
b.catname LIKE '%sales%'
For a single keyword on VARCHAR fields you can use LIKE:
SELECT id, category, location
FROM table
WHERE
(
category LIKE '%keyword%'
OR location LIKE '%keyword%'
)
For a description you're usually better adding a full text index and doing a Full-Text Search (MyISAM only):
SELECT id, description
FROM table
WHERE MATCH (description) AGAINST('keyword1 keyword2')
SELECT
*
FROM
yourtable
WHERE
id LIKE '%keyword%'
OR position LIKE '%keyword%'
OR category LIKE '%keyword%'
OR location LIKE '%keyword%'
OR description LIKE '%keyword%'
OR refno LIKE '%keyword%';
Ideally, have a keyword table containing the fields:
Keyword
Id
Count (possibly)
with an index on Keyword. Create an insert/update/delete trigger on the other table so that, when a row is changed, every keyword is extracted and put into (or replaced in) this table.
You'll also need a table of words to not count as keywords (if, and, so, but, ...).
In this way, you'll get the best speed for queries wanting to look for the keywords and you can implement (relatively easily) more complex queries such as "contains Java and RCA1802".
"LIKE" queries will work but they won't scale as well.
Personally, I wouldn't use the LIKE string comparison on the ID field or any other numeric field. It doesn't make sense for a search for ID# "216" to return 16216, 21651, 3216087, 5321668..., and so on and so forth; likewise with salary.
Also, if you want to use prepared statements to prevent SQL injections, you would use a query string like:
SELECT * FROM job WHERE `position` LIKE CONCAT('%', ? ,'%') OR ...
I will explain the method i usally prefer:
First of all you need to take into consideration that for this method you will sacrifice memory with the aim of gaining computation speed.
Second you need to have a the right to edit the table structure.
1) Add a field (i usually call it "digest") where you store all the data from the table.
The field will look like:
"n-n1-n2-n3-n4-n5-n6-n7-n8-n9" etc.. where n is a single word
I achieve this using a regular expression thar replaces " " with "-".
This field is the result of all the table data "digested" in one sigle string.
2) Use the LIKE statement %keyword% on the digest field:
SELECT * FROM table WHERE digest LIKE %keyword%
you can even build a qUery with a little loop so you can search for multiple keywords at the same time looking like:
SELECT * FROM table WHERE
digest LIKE %keyword1% AND
digest LIKE %keyword2% AND
digest LIKE %keyword3% ...
You can find another simpler option in a thread here: Match Against.. with a more detail help in 11.9.2. Boolean Full-Text Searches
This is just in case someone need a more compact option. This will require to create an Index FULLTEXT in the table, which can be accomplish easily.
Information on how to create Indexes (MySQL): MySQL FULLTEXT Indexing and Searching
In the FULLTEXT Index you can have more than one column listed, the result would be an SQL Statement with an index named search:
SELECT *,MATCH (`column`) AGAINST('+keyword1* +keyword2* +keyword3*') as relevance FROM `documents`USE INDEX(search) WHERE MATCH (`column`) AGAINST('+keyword1* +keyword2* +keyword3*' IN BOOLEAN MODE) ORDER BY relevance;
I tried with multiple columns, with no luck. Even though multiple columns are allowed in indexes, you still need an index for each column to use with Match/Against Statement.
Depending in your criterias you can use either options.
I know this is a bit late but what I did to our application is this. Hope this will help someone tho. But it works for me:
SELECT * FROM `landmarks` WHERE `landmark_name` OR `landmark_description` OR `landmark_address` LIKE '%keyword'
OR `landmark_name` OR `landmark_description` OR `landmark_address` LIKE 'keyword%'
OR `landmark_name` OR `landmark_description` OR `landmark_address` LIKE '%keyword%'