"Where" statement: match a single word (not substring) - mysql

I am using MySQL.
I have a car table in my database, and there is a name column in that table.
Suppose the name column of the table contain values:
+----------+
| name |
+----------+
| AAA BB |
----------
| CC D BB |
----------
| OO kk BB |
----------
| PP B CC |
----------
I would like to search the table where name column value contains word "BB" (not substring), What is the SQL command to achieve this ?
I know LIKE , but it is used to match a contained substring, not for a word match.
P.S.
My table contains large data. So, I probably need a more efficient way than using LIKE
The values in name column are random strings.
Please do not ask me to use IN (...) , because the values in that column is unpredictable.

Try this WHERE clause:
WHERE name LIKE '% BB %'
OR name LIKE 'BB %'
OR name LIKE '% BB'
OR name = 'BB'
Note that this will not perform well if your table is large. You may also want to consider a full-text search if you need better performance.

You can use the REGEXP operator in MySQL:
SELECT *
FROM car
WHERE name REGEXP '[[:<:]]BB[[:>:]]'
It will match BB if it occurs as a single word. From the MySQL manual:
[[:<:]], [[:>:]]
These markers stand for word boundaries. They match the beginning and end of words, respectively. A word is a sequence of word characters that is not preceded by or followed by word characters. A word character is an alphanumeric character in the alnum class or an underscore (_).
mysql> SELECT 'a word a' REGEXP '[[:<:]]word[[:>:]]'; -> 1
mysql> SELECT 'a xword a' REGEXP '[[:<:]]word[[:>:]]'; -> 0

Related

Is it possible to search a column of IDs for 1 if other rows include IDs with 1 in them?

I have a MySQL database with a varchar column (although the column type can be changed if needed).
The column stores some ids separated with underscores like so:
Row 1: 1
Row 2: 1_2_3
Row 3: 10_2
Row 4: 4_5_1
Is there anyway in this structure to query that column for 1 and return all rows with 1 (but not Row 3 which contains 1 but the ID is 10).
To get the current results I am attempting to search the column LIKE %1%.
Or do I need to change the structure to achieve the result I want?
Maybe you can try:
select *
from t
where c like '1\_%'
or c like '%\_1'
or c like '%\_1\_%'
or c = '1'
You need to escape the underscore as \_, since SQL defines it as a wildcard and will match any character.
If we had a comma separator, then we could use MySQL FIND_IN_SET function.
We can use MySQL REPLACE function to change the underscores to commas,
e.g.
SELECT t.*
FROM t
WHERE FIND_IN_SET('1',REPLACE( t.id ,'_',','))
Reference:
https://dev.mysql.com/doc/refman/8.0/en/string-functions.html#function_find-in-set
https://dev.mysql.com/doc/refman/8.0/en/string-functions.html#function_replace
NOTE:
Storing underscore separated lists is an antipattern. See Chapter 2 of Bill Karwin's book "SQL Antipatterns: Avoiding the Pitfalls of Database Programming"
https://www.amazon.com/SQL-Antipatterns-Programming-Pragmatic-Programmers/dp/1934356557
With the operator like:
select * from tablename
where concat('_', id, '_') like '%#_1#_%' escape '#'
See the demo.
Results:
| id |
| ----- |
| 1 |
| 1_2_3 |
| 4_5_1 |

MySQL - Special characters in column value

I got a big data (approximately 600,000).
I want the rows with value "word's" will appear.
Special characters will be completely ignored.
TABLE:
| column_value |
| ------------- |
| word's |
| hello |
| world |
QUERY: select * from table where column_value like '%words%'
RESULTS:
| column_value |
| ------------- |
| word's |
I want the rows with special characters will appear and ignore their special characters.
Can you please help me how can we achieve it with fast runtime?
You can use replace to remove the "special" character prior the matching.
SELECT *
FROM table
WHERE replace(column_value, '''', '') LIKE '%words%';
Nest the replace() calls for other characters.
Or you try it with regular expressions.
SELECT *
FROM table
WHERE column_value REGEXP 'w[^a-zA-Z]*o[^a-zA-Z]*r[^a-zA-Z]*d[^a-zA-Z]*s';
[^a-zA-Z]* matches optional characters, that are not a, ..., y and z and not A, ..., Y and Z, so this matches your search word also with any non alphas between the letters.
Or you have a look at the options full text search brings with it. Maybe that can help too.
You must add an index on your column_value.
MySQL doc

mySQL REGEXP match value between commas

I've been looking into the REGEXP when filtering my entries in my database.
I have a columns with values separated by commas looking like:
id col A
|---|------------------------|
| 1 | P:1,P:2,P:5,P:7 |
| 2 | P:6,P:8,P:10,P:11 |
| 3 | P:4,P:3,P1,P:0 |
| 4 | P:2,P:1 |
|---|------------------------|
Let's say I want the rows containing the value P:1, how can i design a REGEXP in the form:
SELECT * FROM `table` WHERE `col A` REGEXP '?'
so that i get rows 1 3 and 4? My previous approach was simply to use:
SELECT * FROM `table` WHERE `col A` LIKE 'P:1'
However that would naturally also return row 2 because it technically contains P:1...
Any help would be appreciated, I thinking this problem is fairly simple for a regexp expert!Cheers,Andreas
You need to read up on word boundaries.
[[:<:]], [[:>:]]
These markers stand for word boundaries. They match the beginning and end of words, respectively. A word is a sequence of word characters that is not preceded by or followed by word characters. A word character is an alphanumeric character in the alnum class or an underscore (_).

How can I use the LIKE operator on a list of strings to compare?

I have a query I need to run on almost 2000 strings where it would be very helpful to be able to do a list like you can with the "IN" operator but using the LIKE comparison operation.
For example I want to check to see if pet_name is like any of these (but not exact): barfy, max, whiskers, champ, big-D, Big D, Sally
Using like it wouldn't be case sensitive and it can also have an underscore instead of a dash. Or a space. It will be a huge pain in the ass to write a large series of OR operators. I am running this on MySQL 5.1.
In my particular case I am looking for file names where the differences are usually a dash or an underscore where the opposite would be.
For this task I would suggest making use of RegExp capabilities in MySQL like this:
select * from EMP where name RLIKE 'jo|ith|der';
This is case insensitive match and will save from multiple like / OR conditions.
You could do something like this -
SELECT FIND_IN_SET(
'bigD',
REPLACE(REPLACE('barfy,max,whiskers,champ,big-D,Big D,Sally', '-', ''), ' ', '')
) has_petname;
+-------------+
| has_petname |
+-------------+
| 5 |
+-------------+
It will give a non-zero value (>0) if there is a pet_name we are looking for.
But I'd suggest you to create a table petnames and use SOUNDS LIKE function to compare names, in this case 'bigD' will be equal to 'big-D', e.g.:
SELECT 'bigD' SOUNDS LIKE 'big-D';
+---------------------------+
| 'bigD'SOUNDS LIKE 'big-D' |
+---------------------------+
| 1 |
+---------------------------+
Example:
CREATE TABLE petnames(name VARCHAR(40));
INSERT INTO petnames VALUES
('barfy'),('max'),('whiskers'),('champ'),('big-D'),('Big D'),('Sally');
SELECT name FROM petnames WHERE 'bigD' SOUNDS LIKE name;
+-------+
| name |
+-------+
| big-D |
| Big D |
+-------+
As first step put all static values in any temporary table, this would be lookup dictionary.
SELECT * FROM Table t
WHERE EXISTS (
SELECT *
FROM LookupTable l
WHERE t.PetName LIKE '%' + l.Value + '%'
)
Configure the column containing those 2000 values for full-text searching. Then you can use MySQL's full-text search feature. Refer to their docs
You could use REGEXP instead. It worked like a charm for me
pet_name regexp 'barfy|max|whiskers|champ|you name it'

mySQL SELECT IN from string

Here is my table X:
id vals
---------------------
1 4|6|8|
Now table Y:
id name
--------------------
1 a
4 b
6 c
8 d
Now I want the following:
select * from Y where id IN (replace(select vals from X where id = '1'),'|',',')
But this does not seem to work. Any ideas why?
You may use FIND_IN_SET instead of just IN, normal IN keyword couldn't search between comma seperated values within one field.
For example
mysql> select FIND_IN_SET(4, replace('4|6|8|','|',','));
+-------------------------------------------+
| FIND_IN_SET(4, replace('4|6|8|','|',',')) |
+-------------------------------------------+
| 1 |
+-------------------------------------------+
1 row in set (0.00 sec)
Replace gives you a string back - but it's a string value, not a string as in part of your query.
What you can do is instead of using IN, use a REGEXP to match within your original string, for example:
vals REGEXP '[[:<:]]4[[:>:]]'
would be true only if there is a "4" in the original string that isn't part of a larger number (thus if you have 3|44|100 it wouldn't match on "4" but would match on "44").
The [[:<:]] and [[:>:]] are "left side of word" and "right side of word" respectively.
To generate that string, you can do something like...
CONCAT('[[:<:]]', CAST(id AS CHAR), '[[:>:]]')