How could "None" be equal to 0 in mysql? - mysql

I find that in one table the value "None" is equal to 0
mysql> select distinct id from sometable where id="None";
+-------+
| id |
+-------+
| 0 |
+-------+
Note that the type of id is int(7)!
Although all the value is shown as 0 in mysql client, when I use PyMySQL to query records in django, some of them are 0 while others are unicode "None", how could this happen?

MySQL loose with type conversions. When implicitly converting a string to a number, it will take characters from the start of the string as long as they are digits, and ignore the others.
In your example, "None" isn't digits, so MySQL will return 0.
From Mysql type-conversion
For comparisons of a string column with a number, MySQL cannot use an index on the column to look up the value quickly.
Implicitly converting a string is horrible for performance, since you lose the usage on the index you may have on your column
Here is a sample to compare "2arse" string and 2 number, we can see when ID = "2arse" will return ID = 2 row data because it will take digits 2 and ignore arse string to implicitly converting.
Schema (MySQL v5.7)
CREATE TABLE sometable(
ID INT
);
INSERT INTO sometable VALUES (0);
INSERT INTO sometable VALUES (2);
Query #1
select distinct id
from sometable
where ID = "2arse";
| id |
| --- |
| 2 |
View on DB Fiddle

use cast to int then compare
select distinct id from sometable where cast(id AS SIGNED)=0

Related

Connot select rows without double quote using ENUM variable type in MySQL

How to select rows without using the double quotes("1").
I am design the status column in enum type.
status
enum('0', '1')
My Query:
SELECT * FROM `user` WHERE activation_key='123456' AND status="1";
Result :
Display 1 row
I am Try :
SELECT * FROM `user` WHERE activation_key='123456' AND status=1;
Result :
Display 0 row
Is it possible to get the data without double or single quotes in status column?
I am a beginner of MYSQL, Sorry for my bad question!
An enumeration value must be a quoted string literal. And to query a string you must enclose it in quotes.
If you make enumeration values that look like numbers, it is easy to mix up the literal values with their internal index numbers.
numbers ENUM('0','1','2')
If you store 2, it is interpreted as an index value, and becomes '1'
(the value with index 2). If you store '2', it matches an enumeration
value, so it is stored as '2'. If you store '3', it does not match any
enumeration value, so it is treated as an index and becomes '2' (the
value with index 3).
mysql> INSERT INTO t (numbers) VALUES(2),('2'),('3');
mysql> SELECT * FROM t;
+---------+
| numbers |
+---------+
| 1 |
| 2 |
| 2 |
+---------+
More details ENUM in MySQL

MySQL joining tables on fields with different type

Suppose I have 2 InnoDB tables A and B.
Table A has a column named Acountry of type INT
Table B has a column named Bcountry of type VARCHAR
Some records in table A have in column Acountry values "356"
Some records in table B have in column Bcountry values "356,Italy"
How is it possible that the following join works perfectly:
(I mean I get rows where Acountry or Bcountry starts with 356)
SELECT A.Field1 , A.Field2 , B.Field3 , B.Field4
FROM A
JOIN B ON A.Acountry=B.Bcountry
despite the fact that the 2 columns have different values
and are of different type
Any hints ?
Is there any setting for "loose" joining ?
P.S.
I found this link http://bugs.mysql.com/bug.php?id=3777
where it states that:
"This is expected behavior.
The arguments (string and number) are compared as floating-point numbers"
???
Strings in MySQL which begin with numbers will be cast as numbers up to the first non-numeric character. So the cast operation results in only the integer at the front:
> SELECT CAST('356,Italy' AS INT);
+--------------------------+
| CAST('356,Italy' AS INT) |
+--------------------------+
| 356 |
+--------------------------+
(Note: casting as DECIMAL will produce the same result)
But a similar string which has a non-numeric character first will cast to 0:
> SELECT CAST('xx356,Italy' AS INT);
+--------------------------------+
| CAST('xx356,Italy' AS INT) |
+--------------------------------+
| 0 |
+--------------------------------+
I would consider this to be an unreliable behavior to perform a join on, even if it is unlikely to be changed in future MySQL versions. It would be much better to produce a consistent or more directly comparable value between those common columns.
Fix the data if possible:
First and foremost, if you are in any position to change this table structure such that B has consistent data, that is the real solution. And doing that would also allow you to make the data types of A.ACountry and B.BCountry identical (both as INT types) which further allows you to define a proper FOREIGN KEY constraint.
Join with what you have using string operations:
But a JOIN's ON condition can be any arbitrary expression, and MySQL offers a SUBSTRING_INDEX() function to return a substring before a delimiter. You should be able to join successfully using that:
SELECT
A.*,
B.Field3,
B.Field4
FROM
A
-- Join on the first group of characters before `,` in BCountry
INNER JOIN B ON A.ACountry = SUBSTRING_INDEX(BCountry, ',', 1)
This works because:
> SELECT SUBSTRING_INDEX('356,Italy', ',', 1);
+--------------------------------------+
| SUBSTRING_INDEX('356,Italy', ',', 1) |
+--------------------------------------+
| 356 |
+--------------------------------------+
And without the trailing string the same result:
> SELECT SUBSTRING_INDEX('356', ',', 1);
+--------------------------------+
| SUBSTRING_INDEX('356', ',', 1) |
+--------------------------------+
| 356 |
+--------------------------------+
Note: The string operation is likely to degrade performance of this join. Fixing the source data is again the better solution.

MySQL ORDER BY Alphanumeric values, first all integers, then all alphas

searched around awhile for a solution to this problem, but no answer yet.
Have a column of alphanumeric model ID numbers to populate an index in a certain order. Two different attempts with the order they produced:
ORDER BY Model_ID ASC
1278-8
211E
350-50
996
3800P
AP23
AP263
AP26M
JA042
ORDER BY CAST(Model_ID AS UNSIGNED), Model_ID
AP23
AP263
AP26M
JA042
211E
350-50
996
1278-8
3800P
However, I need to have it sorted like so, with all of the integer-starting numbers exhausted first:
211E
350-50
996
1278-8
3800P
AP23
AP263
AP26M
JA042
Help? Thanks
For the sample data, this will get the desired order:
ORDER BY Model_ID+0=0, Model_ID+0, Model_ID ASC
Let's unpack that a bit.
The expression Model_ID+0 evaluates Model_ID in a numeric context, by adding zero to it. Basically, MySQL gets whatever leading characters that can be converted to a number, and disregards the rest. For values that can't be interpreted as a number, MySQL returns 0.
The first expression checks if the numeric value is zero, so those will be sorted last. (MySQL returns numeric value of 1 for boolean TRUE, 0 for FALSE.)
The second expression gets the non-zero values sorted in numeric order.
NOTE: these expressions "work" for the sample data; the edge case is values that have leading zeros as the numeric value, e.g. '000ABC' will be sorted after all the other "numeric" values. And MySQL doesn't stop at just the integer portion, if there's a dot character, that can be interpreted as a decimal point.
You can see the values of the expressions (for testing), by including them in the SELECT list, e.g.
SELECT Model_ID+0=0, Model_ID+0, ...
DROP TABLE IF EXISTS my_table;
CREATE TABLE my_table (model_id VARCHAR(20) NOT NULL PRIMARY KEY);
INSERT INTO my_table VALUES
('1278-8'),
('211E'),
('350-50'),
('996'),
('3800P'),
('AP23'),
('AP263'),
('AP26M'),
('JA042');
SELECT model_id FROM my_table ORDER BY model_id + 0 = 0,model_id + 0;
+----------+
| model_id |
+----------+
| 211E |
| 350-50 |
| 996 |
| 1278-8 |
| 3800P |
| AP23 |
| AP263 |
| AP26M |
| JA042 |
+----------+

mysql strange behavior when inserting data

When inserting data to mysql via the phpmyadmin page, or via python I've seen something I can't explain:
cur.execute("INSERT INTO 28AA507A0500009E (timestamp, temp) VALUES ('2014-01-04 15:36:30',24.44)")
cur.execute("INSERT INTO 28D91F7A050000D9 (timestamp, temp) VALUES ('2014-01-04 15:36:30',24.44)")
cur.execute("INSERT INTO `28012E7A050000F5` (timestamp, temp) VALUES ('2014-01-04 15:36:30',24.44)")
Notice the last entry with the ` around the table name.
The first 2 entry's work fine without the apostrophe.
I can also put the apostrophes around all the table names and it still works.
Why can I remote the apostrophes from the first 2 lines, and not the 3rd one?
The tables are all created equally.
Edit 1:
In due respect to the following comments:
Your explanation is not entirely accurate. There is no alias in
the INSERT statement. I think that the part of the identifier after
28012E7 is just discarded as MySQL tries convert the identifier to
an integer value! – ypercube
these are table names not column names. – Sly Raskal
Well, MySQL sure have discarded the part of the table name identifier. My intention was to bring forward how a identifier name was interpreted when the system could not find it in the list of accessible table names ( I chose column/expression names in my examples ). As the engine interpreted it as a valid number but not as an identifier to represent a table, it threw an exception.
And I chose SELECT to clarify, why the table identifier was rejected for not putting in back quotes. Because it represents a number, it can't be used as an identifier directly, but should be surrounded with back quotes.
MySQL allows to suffix aliases just after numerics, numeric expressions surrounded by braces or literals. To one's surprise, a space between them is optional.
In your case, 28012E7A050000F5 is a valid exponent form ( 28012E7 ) of number 280120000000 suffixed with alias A050000F5. And hence 28012E7A050000F5 can't be used as a column name without back quotes. See following observations:
mysql> -- select 28012E7 as A050000F5;
mysql> select 28012E7A050000F5;
+--------------+
| A050000F5 |
+--------------+
| 280120000000 |
+--------------+
1 row in set (0.00 sec)
Following are some valid examples:
mysql> -- select ( item_count * price ) as v from orders;
mysql> select ( item_count * price )v from orders;
+-----+
| v |
+-----+
| 999 |
+-----+
1 rows in set (0.30 sec)
mysql> -- select ( 3 * 2 ) as a, 'Ravinder' as name;
mysql> select ( 3 * 2 )a, 'Ravinder'name;
+---+----------+
| a | name |
+---+----------+
| 6 | Ravinder |
+---+----------+
1 row in set (0.00 sec)

How to Insert BOOL Value to MySQL Database

I am trying to insert values into a BOOL data type in MySQL (v 5.5.20) using the following script:
CREATE DATABASE DBTest;
USE DBTest;
DROP TABLE IF EXISTS first;
CREATE TABLE first (id INT AUTO_INCREMENT NOT NULL PRIMARY KEY , name VARCHAR(30) ,sale BOOL,);
INSERT INTO first VALUES ("", "G22","TRUE");
INSERT INTO first VALUES ("", "G23","FALSE");
But the INSERT statement just inserts 0 (Zero) to the boolean column for both TRUE and FALSE options! Can you please let me know why this is happening?
TRUE and FALSE are keywords, and should not be quoted as strings:
INSERT INTO first VALUES (NULL, 'G22', TRUE);
INSERT INTO first VALUES (NULL, 'G23', FALSE);
By quoting them as strings, MySQL will then cast them to their integer equivalent (since booleans are really just a one-byte INT in MySQL), which translates into zero for any non-numeric string. Thus, you get 0 for both values in your table.
Non-numeric strings cast to zero:
mysql> SELECT CAST('TRUE' AS SIGNED), CAST('FALSE' AS SIGNED), CAST('12345' AS SIGNED);
+------------------------+-------------------------+-------------------------+
| CAST('TRUE' AS SIGNED) | CAST('FALSE' AS SIGNED) | CAST('12345' AS SIGNED) |
+------------------------+-------------------------+-------------------------+
| 0 | 0 | 12345 |
+------------------------+-------------------------+-------------------------+
But the keywords return their corresponding INT representation:
mysql> SELECT TRUE, FALSE;
+------+-------+
| TRUE | FALSE |
+------+-------+
| 1 | 0 |
+------+-------+
Note also, that I have replaced your double-quotes with single quotes as are more standard SQL string enclosures. Finally, I have replaced your empty strings for id with NULL. The empty string may issue a warning.