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.
Related
the id in MySQL table is uuid, and no id is 1.
A. My query is:
select id, name from xxx_table where id=1
and I get the result:
+--------------------------------------+----------------------+
| id | name |
+--------------------------------------+----------------------+
| 1bdf0336-c5bf-4245-8897-dbda3bf9e202 | xxxxxxxxxxxxxxxxxxxx |
+--------------------------------------+----------------------+
that's not what I want. this id is not 1.
B. my new query:
select id, name from xxx_table where id='1'
and I get Empty set, that is what I want.
What I'm confused is, if it's the format issue of id, why int(1) can match uuid(1bdf0336-c5bf-4245-8897-dbda3bf9e202)?
================================================================
OK. Follow the suggestion of Luuk, when I check
show create table xxx_table;
and I get:
| Table | Create Table |
| xxx_table | CREATE TABLE `xxx_table` (`id` varchar(64) NOT NULL,
...,
PRIMARY KEY (`id`)
)ENGINE=InnoDB DEFAULT CHARSET=utf8
MySQL plays loose with type conversion. When implicitly converting a char to a number.
When an operator is used with operands of different types, type conversion occurs to make the operands compatible. Some conversions occur implicitly.
For example, MySQL automatically converts strings to numbers as necessary, and vice versa.
For example, there is a query like below, you will get result 2 instead of an error from the query.
because Mysql will convert the query like 1 + 1 implicitly.
Query 1:
select '1bdf0336-c5bf-4245-8897-dbda3bf9e202' + 1 res
Results:
| res |
|-----|
| 2 |
this query will compare full string which equals to 1 string type
select id, name from xxx_table where id='1'
The following rules describe how conversion occurs for comparison operations:
1 - If one or both arguments are NULL, the result of the comparison is NULL, except for the NULL-safe <=> equality comparison operator. For NULL <=> NULL, the result is true. No conversion is needed.
2 - If both arguments in a comparison operation are strings, they are compared as strings.
3 - If both arguments are integers, they are compared as integers.
4 - Hexadecimal values are treated as binary strings if not compared to a number.
5 - If one of the arguments is a TIMESTAMP or DATETIME column and the other argument is a constant, the constant is converted to a timestamp before the comparison is performed. This is done to be more ODBC-friendly. Note that this is not done for the arguments to IN()! To be safe, always use complete datetime, date, or time strings when doing comparisons. For example, to achieve best results when using BETWEEN with date or time values, use CAST() to explicitly convert the values to the desired data type.
6 - A single-row subquery from a table or tables is not considered a constant. For example, if a subquery returns an integer to be compared to a DATETIME value, the comparison is done as two integers. The integer is not converted to a temporal value. To compare the operands as DATETIME values, use CAST() to explicitly convert the subquery value to DATETIME.
7 - If one of the arguments is a decimal value, comparison depends on the other argument. The arguments are compared as decimal values if the other argument is a decimal or integer value, or as floating-point values if the other argument is a floating-point value.
8 - In all other cases, the arguments are compared as floating-point (real) numbers.
type-conversion
After the SELECT ... you will see x warnings. Use SHOW WARNINGS to find out about those warnings:
mysql> select * from xxx_table where id=12;
+--------------------------------------+
| id |
+--------------------------------------+
| 12a1c7d5-6dfa-11ec-9124-309c23b7280c |
+--------------------------------------+
1 row in set, 5 warnings (0.00 sec)
mysql> show warnings;
+---------+------+--------------------------------------------------------------------------+
| Level | Code | Message |
+---------+------+--------------------------------------------------------------------------+
| Warning | 1292 | Truncated incorrect DOUBLE value: '12a1c7d5-6dfa-11ec-9124-309c23b7280c' |
This can also be seen when doing:
mysql> select id, cast(id as unsigned) from xxx_table;
+--------------------------------------+----------------------+
| id | cast(id as unsigned) |
+--------------------------------------+----------------------+
| 12a1c7d5-6dfa-11ec-9124-309c23b7280c | 12 |
| 13392fc5-6dfa-11ec-9124-309c23b7280c | 13392 |
| 13ad01fd-6dfa-11ec-9124-309c23b7280c | 13 |
| 1425df26-6dfa-11ec-9124-309c23b7280c | 1425 |
| 14a139e8-6dfa-11ec-9124-309c23b7280c | 14 |
+--------------------------------------+----------------------+
5 rows in set, 5 warnings (0.00 sec)
P.S. The long story is about type conversion, see other answer.
The other answers have dealt with the type-conversion in plenty of detail so I thought I would suggest that you look at the other issue. Why are you storing UUID in a varchar? It may be easy but it is very inefficient as you significantly increase the size of all your indices. Storing them in a BINARY(16) would make more sense.
CREATE TABLE `uuid_tests` (
`uuid` BINARY(16) NOT NULL PRIMARY KEY,
`string` CHAR(36) NOT NULL
);
INSERT INTO uuid_tests VALUES
(UUID_TO_BIN('1bdf0336-c5bf-4245-8897-dbda3bf9e202'), '1bdf0336-c5bf-4245-8897-dbda3bf9e202');
SELECT * FROM uuid_tests WHERE uuid = UUID_TO_BIN('1bdf0336-c5bf-4245-8897-dbda3bf9e202');
SELECT * FROM uuid_tests WHERE uuid = 1;
SELECT * FROM uuid_tests WHERE string = '1bdf0336-c5bf-4245-8897-dbda3bf9e202';
SELECT * FROM uuid_tests WHERE string = 1;
As you are using UUIDs as PK it is worth reading about the second argument to both BIN_TO_UUID and UUID_TO_BIN
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
I have table field with enum enum('0','1','2','3','4','5','6').
In query when I try with IN (1) it is not working but when I use IN ("1") it is working.
If I use In (1,2) it is working.
So when there is one value in "IN" clause then it should work without quote
ENUM values are defined and stored as strings. They can be accessed via their string value or via their numeric index value (which starts at 1 and not 0).
Your enum values start at '0' which would have a numeric index value of 1. So, it would be possible to get some data back from your query using IN(1,2) but those numbers will be treated as the index and you will actually get data returned for records where the enum values are '2' and '3' (probably not what you think you are getting back).
IN(1) doesn't work because you have no data with an index value of 1 (emum value = '0')
IN('1') does work because you do have data with an enum value of '1'
Try this for a practical example
http://sqlfiddle.com/#!9/3993b/1
or read the section on Handling of Enumeration Literals in the mysql documentation
You can use values as string or integer, IN() function support both types.
The IN operator allows you to specify multiple values in a WHERE clause.
Usually IN() function is using for multiples values but it does support single value also. For me all queries are working
SELECT * FROM `your_table` WHERE `id` IN('4') // String Number
SELECT * FROM `your_table` WHERE `id` IN('4','2','1') // String Multiple Number
SELECT * FROM `your_table` WHERE `id` IN(1) // Single Integer
SELECT * FROM `your_table` WHERE `id` IN(1,2,4) // Multiple Integer
Avoid using number as 'enumeration values'
Doucumenation quotes-We strongly recommend that you do not use numbers as enumeration values, because it does not save on storage over the appropriate TINYINT or SMALLINT type, and it is easy to mix up the strings and the underlying number values (which might not be the same) if you quote the ENUM values incorrectly. If you do use a number as an enumeration value, always enclose it in quotation marks. If the quotation marks are omitted, the number is regarded as an index. See Handling of Enumeration Literals to see how even a quoted number could be mistakenly used as a numeric index value.'
Link- https://dev.mysql.com/doc/refman/5.7/en/enum.html#enum-limits
enum supports accessing values either by numeric index of values or values that are directly quoted.
As per MySQL documentation on ENUM:
... strongly recommend that you do not use numbers as enumeration values,
because it does not save on storage over the appropriate TINYINT or SMALLINT type,
and it is easy to mix up the strings and the underlying number values
(which might not be the same) if you quote the ENUM values incorrectly.
If you do use a number as an enumeration value, always enclose it in quotation marks.
If the quotation marks are omitted, the number is regarded as an index.
Examples:
mysql> drop table if exists so_q48786040;
mysql> CREATE TABLE so_q48786040(e ENUM('6', '5', '4', '3', '2', '1', '0'));
mysql> INSERT INTO so_q48786040 VALUES( 2 ), ( 4 ), ( 7 ), ( '6' );
Query OK, 4 rows affected (0.05 sec)
Records: 4 Duplicates: 0 Warnings: 0
Selecting all rows, returns values 5,3,0,6
mysql> SELECT * FROM so_q48786040;
+------+
| e |
+------+
| 5 |
| 3 |
| 0 |
| 6 |
+------+
4 rows in set (0.00 sec)
Selecting at specific indices. Results will be in the order of enum indices defined.
mysql> SELECT * FROM so_q48786040 WHERE e IN( 7, 4 );
+------+
| e |
+------+
| 3 | -- <--- at index 4
| 0 | -- <--- at index 7
+------+
2 rows in set (0.00 sec)
Selecting at specific quoted literals. Results will be in the order of enum indices defined.
mysql> SELECT * FROM so_q48786040 WHERE e IN( '6', '3', '0' );
+------+
| e |
+------+
| 3 |
| 0 |
| 6 |
+------+
3 rows in set (0.00 sec)
Selecting a non existing entry. Returns empty set as '4' was not inserted
mysql> SELECT * FROM so_q48786040 WHERE e IN( '4' );
Empty set (0.00 sec)
NOTE:
It is suggested to define empty literals at index 0.
The index of the NULL value is NULL.
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
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 |
+----------+