例如 - 我从cli创建数据库和表并插入一些数据:
CREATE DATABASE testdb CHARACTER SET 'utf8' COLLATE 'utf8_general_ci';
USE testdb;
CREATE TABLE test (id INT, str VARCHAR(100)) TYPE=innodb CHARACTER SET 'utf8' COLLATE 'utf8_general_ci';
INSERT INTO test VALUES (9, 'some string');
现在我可以这样做,这些例子确实有用(所以 - 引号不会影响它看起来的任何东西):
SELECT * FROM test WHERE id = '9';
INSERT INTO test VALUES ('11', 'some string');
所以 - 在这些例子中,我通过字符串选择了一行,实际在mysql中存储为INT,然后我在一个INT列中插入了一个字符串
我不明白为什么它的工作方式与此相同。为什么允许将字符串插入INT列?
我可以将所有Mysql数据类型作为字符串插入吗?
这种行为在不同的RDBMS中是否是标准的?
谢谢!
答案 0 :(得分:60)
MySQL与PHP非常相似,并且会尽可能地自动转换数据类型。由于您正在使用int字段(左侧),它将尝试透明地将参数的右侧转换为int,因此'9'
变为9
}。
严格来说,引号是不必要的,并强制MySQL进行类型转换/转换,因此浪费了一点CPU时间。实际上,除非您运行的是Google大小的操作,否则这种转换开销在显微镜下会很小。
答案 1 :(得分:8)
你永远不应该在数字周围加上引号。这是有正当理由的。
真正的问题归结为类型转换。当您将数字放在引号内时,它被视为一个字符串,MySQL必须将它转换为一个数字才能执行查询。虽然这可能需要很短的时间,但是当MySQL没有很好地转换你的字符串时,真正的问题就开始发生了。例如,MySQL会将基本字符串(如'123')转换为整数123,但会将一些较大的数字(如'18015376320243459')转换为浮点数。由于浮点可以舍入,因此查询可能会返回不一致的结果。 Learn more about type casting here。根据您的服务器硬件和软件,这些结果会有所不同。 MySQL解释了这一点。
如果您担心SQL注入,请始终先检查该值,然后使用PHP删除任何非数字。您可以使用preg_replace:preg_replace("/[^0-9]/", "", $string)
此外,如果您使用引号编写SQL查询,它们将无法在PostgreSQL或Oracle等数据库上运行。
答案 2 :(得分:3)
这不是标准行为。
对于MySQL 5.5。这是默认的SQL模式
mysql> select @@sql_mode;
+------------+
| @@sql_mode |
+------------+
| |
+------------+
1 row in set (0.00 sec)
Oracle和PostgreSQL更严格地使用ANSI和TRADITIONAL。 The SQL Modes MySQL permits must be set 如果只有,您希望使SQL更符合ANSI标准。否则,你不必触摸任何东西。我从来没有这样做过。
答案 3 :(得分:3)
AFAIK它是标准的,但它被认为是不好的做法,因为
- 在WHERE子句中使用它将阻止优化器使用索引(解释计划应该显示)
- 数据库必须做额外的工作才能将字符串转换为数字
- 如果你将它用于浮点数('9.4'),如果客户端和服务器使用不同的语言设置(9.4 vs 9,4),你将遇到麻烦
简而言之:不要这样做(但是YMMV)
答案 4 :(得分:3)
检查一下,你可以更好地理解......
mysql> EXPLAIN SELECT COUNT(1) FROM test_no WHERE varchar_num=0000194701461220130201115347;
+----+-------------+------------------------+-------+-------------------+-------------------+---------+------+---------+--------------------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+------------------------+-------+-------------------+-------------------+---------+------+---------+--------------------------+
| 1 | SIMPLE | test_no | index | Uniq_idx_varchar_num | Uniq_idx_varchar_num | 63 | NULL | 3126240 | Using where; Using index |
+----+-------------+------------------------+-------+-------------------+-------------------+---------+------+---------+--------------------------+
1 row in set (0.00 sec)
mysql> EXPLAIN SELECT COUNT(1) FROM test_no WHERE varchar_num='0000194701461220130201115347';
+----+-------------+------------------------+-------+-------------------+-------------------+---------+-------+------+-------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+------------------------+-------+-------------------+-------------------+---------+-------+------+-------------+
| 1 | SIMPLE | test_no | const | Uniq_idx_varchar_num | Uniq_idx_varchar_num | 63 | const | 1 | Using index |
+----+-------------+------------------------+-------+-------------------+-------------------+---------+-------+------+-------------+
1 row in set (0.00 sec)
mysql>
mysql>
mysql> SELECT COUNT(1) FROM test_no WHERE varchar_num=0000194701461220130201115347;
+----------+
| COUNT(1) |
+----------+
| 1 |
+----------+
1 row in set, 1 warning (7.94 sec)
mysql> SELECT COUNT(1) FROM test_no WHERE varchar_num='0000194701461220130201115347';
+----------+
| COUNT(1) |
+----------+
| 1 |
+----------+
1 row in set (0.00 sec)
答案 5 :(得分:1)
你不需要引用这些数字,但如果你这样做的话,它总是一个好习惯。
答案 6 :(得分:0)
问题是,让我们说我们有一个名为users的表,如果你运行这个查询,它有一个名为current_balance的FLOAT类型的列:
UPDATE `users` SET `current_balance`='231608.09' WHERE `user_id`=9;
current_balance字段将更新为231608,因为MySQL进行了舍入,类似于您尝试此查询:
UPDATE `users` SET `current_balance`='231608.55' WHERE `user_id`=9;
current_balance字段将更新为231609
答案 7 :(得分:0)
这取决于列的类型! 如果您运行
SELECT * FROM `users` WHERE `username` = 0;
在mysql / maria-db中,您将获得username
不为空的所有记录。
如果列的类型为字符串(char,varchar,...),则始终引用值,否则会得到意外的结果!