MySQL Comparisons and '%' - mysql

Will the following query evaluate to true (1), false (0), or NULL?
SELECT '%' LIKE ' % ';
the answer provided is
The '%' character is matched by '%', but not by the space characters surrounding it, so the expression evaluates to false.
+----------------+
| '%' LIKE ' % ' |
+----------------+
| 0 |
+----------------+
but i thought % can match zero or more characters? so % can match % + Spaces? or does characters nt include wildcards?
UPDATE:
oh but if the comparison happens the other way arnd it is true ... hmm ...
SELECT ' % ' LIKE '%';
Any non-NULL string is matched by the '%' metacharacter, so the expression evaluates to true.
+----------------+
| ' % ' LIKE '%' |
+----------------+
| 1 |
+----------------+

Logic is wrong. You had to write
select ' % ' like '%'
If you are writing like ' % ', it means that in first string must be space, then any symbols and one more space in the end. Wildcards is for like statement, in first string it's not wildcard but symbol.

Not entirely sure what your question is, but example time:
Sample table, mytbl:
col1
----
abc
def
feh
zba
a b
Query1
------
select * from mytbl where col1 like '%b%'
Result1
-------
abc
zba
a b
Query2
------
select * from mytbl where col1 like '%b'
Result2
------
a b
Query3
------
select * from mytbl where col1 like 'a%'
Result3
-------
abc
a b
Query4
------
select * from mytbl where col1 like '% b%'
Result4
-------
a b
Query5
------
select * from mytbl where col1 like '% b %'
Result5
-------
null
As you can see, the % matches zero or more characters. Non-% characters are treated as literals. So that means % b % is looking for anything + space + b + space + anything.
Hopefully, this helps.

Related

How to select all longer, shorter versions of the string, as well as the string itself

What would be the most elegant way to get all entries to a given record that are "longer", "shorter" or the same.
Here is an example:
Table 1
"1234567"
"123456"
"12345"
"12346"
"12355"
"123"
"12"
Suppose the original is "12345". Then I would like to select "1234567", "123456" (the longer versions), "123", "12" (The shorter versions) as well as the original "12345" from Table 1, but NOT "12346" and "12355".
I know how to do it using two queries, but is this possible to select the records with a single query?
You can use the following:
SELECT col1,
CASE WHEN col1 LIKE '12345%' AND LENGTH(col1) > LENGTH('12345') THEN 'longer'
WHEN col1 LIKE '12345%' AND LENGTH(col1) = LENGTH('12345') THEN 'same'
WHEN '12345' LIKE CONCAT(col1, '%') AND LENGTH(col1) < LENGTH('12345') THEN 'shorter'
ELSE '' END AS compared_length
FROM test
demo: https://www.db-fiddle.com/f/jzaz6GpfgZ3iBcnjiApybL/0
You can use two LIKE conditions:
select *
from t
where t.str like '12345%'
or '12345' like concat(t.str, '%')
Demo: https://rextester.com/FGKMC15900
Read it as: Select all rows where the column value starts with the "original" string or the "original" string starts with the column value.
Here is an alternative version, that uses a WHERE clause with a REGEXP to filter out unrelevant records ; then, all that is left to do is compare the lenghts of the strings :
SELECT
col1,
CASE
WHEN LENGTH(col1) > LENGTH(#match) THEN 'longer'
WHEN LENGTH(col1) < LENGTH(#match) THEN 'shorter'
ELSE 'same'
END result
FROM mytable
WHERE col1 REGEXP #match OR #match REGEXP col1
Demo on DB Fiddle :
SET #match = '12345';
SELECT
col1,
CASE
WHEN LENGTH(col1) > LENGTH(#match) THEN 'longer'
WHEN LENGTH(col1) < LENGTH(#match) THEN 'shorter'
ELSE 'same'
END result
FROM mytable
WHERE col1 REGEXP #match OR #match REGEXP col1;
| col1 | result |
| ------- | ------- |
| 1234567 | longer |
| 123456 | longer |
| 12345 | same |
| 123 | shorter |
| 12 | shorter |

Combine "replace" and wildcards in SQL query

Within a table like this:
ID| ph_number
-----------
1 | 51231234
2 | 5123 1234
3 | 51231234; 61231234
4 | 5123 1234; 61231234
5 | 5123 1934; 6123 1234
6 | 5123 1234; 6123 1234
7 | aargh; 5123 1234; 6123 1234
, user needs to find a phone number (ex 51231234) not knowing where the spaces are, or if there are many numbers per field. I can find the numbers without spaces with query like this:
SELECT ID, ph_number FROM test WHERE REPLACE(ph_number, ' ', '') LIKE REPLACE('51231234', ' ', '')
that returns IDs 1 and 2, or
SELECT ID, ph_number FROM test WHERE ph_number LIKE '%51231234%'
that returns IDs 1 and 3. But Needed are IDs 1,2,3,4, 6 and 7. I'm not able to combine the two queries. Have tried:
SELECT ID, ph_number FROM test WHERE REPLACE(ph_number, ' ', '') LIKE ('%' + REPLACE('51231234', ' ', '') + '%') // returns 1 & 2
SELECT ID, ph_number FROM test WHERE REPLACE(ph_number, ' ', '') LIKE '%' + REPLACE('51231234', ' ', '') + '%' // returns ERROR
How could I achieve this? I wouldn't want to tell users that they can't have multiple numbers on the field.
In MySQL "+" is exclusively an arithmetic operator. Use the CONCAT() function to concatenate strings:
....WHERE REPLACE(ph_number, ' ', '') LIKE CONCAT('%', REPLACE('51231234', ' ', ''), '%')

Mysql like '%search%' not found with concat colums

I create this table:
create table if not exists `example`(
`firstNames` varchar(45) not null,
`secondNames` varchar(45) not null)
ENGINE = InnoDB;
Now I insert one row:
insert into example values('Jose Alonzo', 'Pena Palma');
And a check if is correct
select * from example;
| firstNames | secondNames |
----------------------------
| Jose Alonzo| Pena Palma |
Its ok!
Easy
Now I create a statment to search this row
set #search = 'jose alonzo pena';
select * from example
where concat(firstNames, ' ', secondNames) like concat('%',#search,'%');
This return
| firstNames | secondNames |
----------------------------
| Jose Alonzo| Pena Palma |
Now I change the value #search for 'jose pena'
set #search = 'jose pena';
select * from example
where concat(firstNames, ' ', secondNames) like concat('%',#search,'%');
And do not return nothing!
| firstNames | secondNames |
What is happening?
I can't use like for characters that are in the middle of the varchar?
No, you cannot use like for characters that are in the middle of the string. Or, in other words, a space character matches a space character, not an arbitrary string of characters. The following would match:
where concat(firstNames, ' ', secondNames) like concat('%', replace(#search, ' ', '%'), '%')
The order would be important, so this would match concat(firstNames, ' ', secondNames) but not concat(secondNames, ' ', firstNames).
If you are interested in these types of searches, you should investigate full text indexes. In addition to being more powerful, they are also faster.

Create search query

I have a table named Customers with columns FirstName, LastName, Email
Let's pretend I have the customer: John | Williams | johnW1234#gmail.com
Now how do I have to create my query so that if I search for:
"williams" => match
"will john" => Match
"will john 55" => NO match
"will 1234" => match
my query right now looks like:
SELECT * FROM `Customers` WHERE `FirstName` LIKE _search_ OR `LastName` LIKE _search__
But if someone where to look for "will john" then my query will return no matches
Seems like you want to do something like that:
select * from Customers where
(FirstName like concat('%','john', '%') and LastName like concat('%','smith', '%'))
or
(LastName like concat('%','john', '%') and FirstName like concat('%','smith', '%'))
The parts: john and smith (in the query) are the different parts of the search term which is exploded by spaces and modified to lowercase (you can do it either in the code or in the DB).
Link to Fiddle
I think this works:
select * from Customers
where (_search_ regexp '^[^ ]+ [^ ]+$' or _search_ regexp '^[^ ]+$')
and (LastName like concat(substring_index(_search_, ' ', 1), '%'))
or FirstName like concat(substring_index(_search_, ' ', -1), '%')));
Dynamic sql can help you
EXECUTE 'SELECT * FROM Customers WHERE FirstName LIKE ' ||
_search_ || ' OR LastName LIKE ' || _search__ || ';';
"_ search _" should be converted to text (explicitly or not).
Of course, quotation waiting for your attention.
Crudely...
SET #string = 'John|Williams|johnW1234#gmail.com';
SELECT IF(#string LIKE "%will%",IF(#string LIKE "%john%",IF(#string LIKE "%55%",1,0),0),0)x;
+---+
| x |
+---+
| 0 |
+---+
SELECT IF(#string LIKE "%will%",IF(#string LIKE "%john%",IF(#string LIKE "%12%",1,0),0),0)x;
+---+
| x |
+---+
| 1 |
+---+

How to string-compare for a single space

I want to check whether a column has any values that are a single space character.
I initially thought that
WHERE my_column = ' '
would be sensible. But no. That will also match columns which have multiple spaces for some reason:
SELECT ' ' = ' ' => true
So I can use a regular express or hex encoding to test:
WHERE HEX(my_column) = '20'
WHERE my_column REGEXP '^\ $'
Both work. But I suspect both (certainly the latter) will be quite inefficient.
Is there a better way?
A BINARY comparison of the two strings is required for an exact match
Under normal circumstances, trailing whitespace is not regarded in the comparison, but the BINARY operator forces it to be:
BINARY also causes trailing spaces to be significant.
mysql> SELECT BINARY ' ' = ' ';
+--------------------+
| BINARY ' ' = ' ' |
+--------------------+
| 0 |
+--------------------+
Incidentally, it isn't just whitespace-only comparisons that are affected by the trailing whitespace issue:
mysql> SELECT 'abc ' = 'abc';
+------------------+
| 'abc ' = 'abc' |
+------------------+
| 1 |
+------------------+
...but...
mysql> SELECT BINARY 'abc ' = 'abc';
+-------------------------+
| BINARY 'abc ' = 'abc' |
+-------------------------+
| 0 |
+-------------------------+
...and even more confusingly, leading whitespace is significant:
mysql> SELECT ' abc ' = 'abc';
+-------------------+
| ' abc ' = 'abc' |
+-------------------+
| 0 |
+-------------------+
Regarding indexing:
BINARY will prevent an index from being used on the character column. However, a note on the docs suggests that the index will be used if the BINARY operator is applied to the string literal side of the comparison as in:
SELECT * FROM `tbl` WHERE `col` = BINARY 'string '
where my_column = ' ' and LENGTH(my_column) = 1
SELECT CASE WHEN COL_NAME='' THEN 'yes' ELSE 'no' END AS SPACE_INDICATOR FROM Table_NAME WHERE LENGTH(COL_NAME)=1;