mysql - 报价数字与否?

时间:2011-07-21 19:58:40

标签: mysql sql ansi-sql

例如 - 我从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中是否是标准的?

谢谢!

8 个答案:

答案 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,...),则始终引用值,否则会得到意外的结果!