In MySQL, why does the following query return '----', '0', '000', 'AK3462', 'AL11111', 'C131521', 'TEST', etc.?
select varCharColumn from myTable where varCharColumn in (-1, '');
I get none of these results when I do:
select varCharColumn from myTable where varCharColumn in (-1);
select varCharColumn from myTable where varCharColumn in ('');
Note: I'm using MySQL version 5.0.45-log (show variables like "%version%";)
Note 2: I tried this on a number column as well, but I do not get unexpected results there.
Your expression is:
where varCharColumn in (-1, '')
The list has to have consistent types. The first element says "this is a list of integers", so the second value is converted to an integer. And '' becomes 0.
In fact, any alphanumeric string that starts with a non-digit is also converted to 0 for an integer comparison. So, you have this situation
'A' in (0) --> TRUE
'B' in (0) --> TRUE
'A' in ('B') --> FALSE
You can readily test this with:
select 'A' in (0) union all
select 'B' in (0) union all
select 'A' in ('B');
You can see it in action with a column:
select val in (0), val in ('0'), val in (0, '')
from (select 'A' as val) t
This returns true, false, true. However, note that val in (-1, 'B') returns FALSE in this case. MySQL is treating the empty string differently from a real string, perhaps inconsistently with the documentation.
That this is true with columns is exhibited by:
select val in (0)
from (select 'A' as val) t;
Who said logic can't be fun?
To fix this, make the list all be of consistent types, probably by putting single quotes around the numbers.
As documented under Comparison Functions and Operators:
You should never mix quoted and unquoted values in an IN list because the comparison rules for quoted values (such as strings) and unquoted values (such as numbers) differ. Mixing types may therefore lead to inconsistent results. For example, do not write an IN expression like this:
SELECT val1 FROM tbl1 WHERE val1 IN (1,2,'a');
Instead, write it like this:
SELECT val1 FROM tbl1 WHERE val1 IN ('1','2','a');
Related
Database is MySQL 5.6
CREATE TABLE set_t
(
set_r SET ('a', 'b', 'c')
);
INSERT INTO set_t (set_r) VALUES ('a,b,c'), ('a,b');
In my case i know only 'a' and 'b'.
For example, need to select row where set_r is "a,b,c".
Value 'c' is unknown, cant use it in query.
Values order is unknown also. They are may be set_r SET ('c', 'b', 'a') or else.
How to select rows, which contains unknown values?
The easy way to do it for your sample data is with NOT IN:
SELECT *
FROM set_t
WHERE set_r NOT IN ('a', 'b', 'a,b')
But this does not scale well if you have larger set and you want to include more members than a and b in the list of known members.
Every member of a set is stored as a numeric value.
In your set the numeric values are:
SET Member Decimal Value Binary Value
'a' 1 001
'b' 2 010
'c' 4 100
So, a value like 'a,b' is stored as 3 (Binary 011)
and a value like 'a,b,c' is stored as 7 (Binary 111)
If you know the numeric values of the known members, which you can get by the order they are defined in the set, then you can use bit operations to get what you want:
SELECT *
FROM set_t
WHERE set_r | 3 <> 3 -- 3 is the numeric value of 'a,b'
or:
SELECT *
FROM set_t
WHERE set_r | 0b11 <> 0b11 -- 0b11 is the numeric binary value of 'a,b'
See the demo.
You can use find_in_set() to check for individual values. See SET documentation here
select * from set_t where find_in_set('a', set_r) and find_in_set('b', set_r)
This gives you
set_r
(a,b,c)
(a,b)
See this db<>fiddle
If you don't want the second row, you can add and not like 'a,b'.
The most efficient method is to use the binary comparisons. This assumes that you know the position of 'a' and 'b' in the set:
select *
from set_t
where (set_r | b'11') <> b'11';
You can also do this using string operations. This is a bit of a pain, because you need to handle the comma delimiter:
select *
from set_t
where replace(replace(replace(concat(',', set_r, ','), ',a,', ','), ',b,', ','), ',', '') <> ''
The logic is:
Put delimiters at the beginning and end of set_r.
Remove delimited elements, replacing them with the delimiter.
Check if the result only has delimiters.
This version works regardless of the size of the set and the position of the elements you want to compare against.
Here is a db<>fiddle.
It is necessary to select rows from the table that contain one substring (or substrings) and do not contain others. It is important to make one expression.
Google says that regular expression like ^(?=.*subs1)(?!.*subs2)$ can work but it doesn't work for me (also tested on https://regexr.com/)
For example
SELECT * FROM TABLE WHERE target_string REGEXP "^(?=.*subs1)(?!.*subs2)$"
bla/subs1/bla/bla -> true (return as query result)
bla/subs1/bla/subs2 -> false
bla/bla/subs2/bla -> false
2 conditions in one expression do not work (separately, work)
Thanks for help!
WHERE foo LIKE '%123%'
AND foo NOT LIKE '%234%'
WHERE foo REGEXP '123[^4]' -- rejects '1234', but accepts '123x234' -- OK?
(This should work in all versions of MySQL or MariaDB.)
I have a column STR which may contain any strings. I'm using MySql. How to find strings which don't contain letters in SQL without using Regular Expressions? As I understand RegExp in SQL is [^...].
So how to select the strings without using [^...]?
Regexp is the most sensible way of doing this. An alternative without...
SELECT STR
FROM YourTable
WHERE NOT EXISTS (SELECT *
FROM (SELECT 'A' AS C
UNION ALL
SELECT 'B'
UNION ALL
SELECT 'C'
/* Todo. Add remaining letters */
) Chars
WHERE INSTR(STR, C) > 0)
I am not sure which RDBMS you're using. But, if you do not want to use regular expression, you can loop through every character in the string and check the ASCII code. If they are only falling in the range 48 to 57, they are only numbers.
Note : This may be very costly operation
From select statement, in a filed I want to remove last characters is character if its number. Is there string function available in MySQL?
for these two SQL I want
test
as output
select 'test1';
select 'test';
Another way is to use REGEXP,
SET #val = 'test12';
SELECT CONCAT(LEFT(#val, CHAR_LENGTH(#val) - 1),
IF(RIGHT(#val, 1) REGEXP '[0-9]' = 0, RIGHT(#val, 1), ''))
SQLFiddle Demo
SQLFiddle Demo (another example)
To remove the last character if it's numeric, one way to do this without using a regular expression is with LEFT, RIGHT and LENGTH :
select if( right(yourfield,1) = 0 && right(yourfield,1) != '0',
yourfield,
left(yourfield, length(yourfield) - 1))
from yourtable;
To replace all trailing numeric values, you can use REVERSE:
select if( cast(reverse(yourfield) as signed) = 0 && right(yourfield,1) != '0',
yourfield,
left(yourfield, length(yourfield) - length((reverse(yourfield) + 0))))
from yourtable;
SQL Fiddle Demo
When casting fields as integers/signed in MySQL, it will cast all the numeric characters up to the first non-numeric character -- thus making the REVERSE work. If the last character is not numeric, it results in 0.
Using the IF check above, if the last character isn't numeric, then it prints the original value, else it prints all but the last character.
here is a pointer:
use a union between two queries.
in the first - either use REGEX, or grab the substr of the field where another substr for the last char is a number,
then union the text field where the substr of the last char is not a number.
You might want to use Regular Expressions inside MySQL. This package might help you https://launchpad.net/mysql-udf-regexp. However, I do not recommend to do it inside MySQL statement as it might be slow. You would better to do it after grabbing the value inside your programming language.
I'd like to select rows from the database where the last character in the mov_id column equals to 1 and 2.
How would the query look like?
SELECT * FROM `myTable` WHERE `mov_id` LIKE '%1' OR `mov_id` LIKE '%2'
the % character is a wildcard which matches anything (like * in many other places)
If mov_id is a numeric value (TINYINT, INT, etc...) then you should use a numeric operator. For instance, use the modulo operator to keep the last digit
SELECT * FROM mytable
WHERE (mov_id MOD 10) IN (1, 2)
If mov_id is a string, you can use LIKE or SUBSTRING(). SUBSTRING() will be slightly faster.
SELECT * FROM mytable
WHERE SUBSTRING(mov_id, -1) IN ('1', '2')
If your table is big or that query is frequently run, you should definitely consider adding a column to your table, in which you would store mov_id's last digit/character, and index that column.
Try this way too:
SELECT field1
FROM table
WHERE RIGHT(field1, 1) = 'x'
it displays the fields that has last a value of x.
SELECT *
FROM Table
WHERE RIGHT(Column_name, 1) IN ('x')
if you want to match two character just replace 1 by 2.
In general:
RIGHT(COLUMN_NAME, NO_OF_CHARACTER_YOU WANT_TO_MATCH_FROM_LAST)
And if you want to match the starting char just use LEFT instead of RIGHT
You could also do something like:
select
your, fields, go, here
from table
where
substring(mov_id, (char_length(move_id) - 1)) = x
SELECT * FROM table WHERE mov_id REGEXP '1$' OR mov_id REGEXP '2$'