53

例如 - 我从 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?

4

8 回答 8

65

MySQL 很像 PHP,并且会尽可能地自动转换数据类型。由于您正在使用 int 字段(左侧),它会尝试将参数的右侧透明地转换为 int ,因此'9'只需变为9.

严格来说,引号是不必要的,并且会强制 MySQL 进行类型转换/转换,因此会浪费一些 CPU 时间。实际上,除非您运行的是 Google 规模的操作,否则这种转换开销将非常小。

于 2011-07-21T20:02:14.957 回答
11

你不应该在数字周围加上引号。这是有正当理由的。

真正的问题归结为类型转换。当您将数字放在引号内时,它被视为字符串,MySQL 必须将其转换为数字才能执行查询。虽然这可能需要一点时间,但当 MySQL 不能很好地转换字符串时,真正的问题就会开始出现。例如,MySQL 会将基本字符串(如 '123')转换为整数 123,但会将一些较大的数字(如 '18015376320243459')转换为浮点数。由于浮点可以四舍五入,因此您的查询可能会返回不一致的结果。在此处了解有关类型转换的更多信息。根据您的服务器硬件和软件,这些结果会有所不同。MySQL 解释了这一点。

如果您担心 SQL 注入,请始终先检查值并使用 PHP 去除任何非数字。您可以为此使用 preg_replace :preg_replace("/[^0-9]/", "", $string)

此外,如果您使用引号编写 SQL 查询,它们将无法在 PostgreSQL 或 Oracle 等数据库上运行。

于 2016-07-22T14:20:08.510 回答
4

看看这个,你可以更好地理解...

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)
于 2013-04-23T07:53:17.147 回答
3

这不是标准行为。

对于 MySQL 5.5。这是默认的 SQL 模式

mysql> select @@sql_mode;
+------------+
| @@sql_mode |
+------------+
|            |
+------------+
1 row in set (0.00 sec)

Oracle 和 PostgreSQL 更严格地使用 ANSI 和 TRADITIONAL。必须设置 MySQL 允许的 SQL 模式 ,如果且仅当您想让 SQL 更符合 ANSI 时。否则,您不必触摸任何东西。我从来没有这样做过。

于 2011-07-21T20:04:36.167 回答
3

AFAIK 这是标准的,但它被认为是不好的做法,因为
- 在 WHERE 子句中使用它会阻止优化器使用索引(解释计划应该显示)
- 数据库必须做额外的工作才能将字符串转换为数字
- 如果您将其用于浮点数('9.4'),如果客户端和服务器使用不同的语言设置(9.4 vs 9,4),您将遇到麻烦

简而言之:不要这样做(但 YMMV)

于 2011-07-21T20:05:01.540 回答
1

这取决于列类型!如果你跑

SELECT * FROM `users` WHERE `username` = 0;

在 mysql/maria-db 中,您将获得所有usernameIS NOT NULL 的记录。

如果列是字符串类型(char、varchar、...),请始终引用值,否则您会得到意想不到的结果!

于 2019-02-12T04:00:33.367 回答
0

你不需要引用这些数字,但如果你这样做,它总是一个好习惯,因为它是一致的。

于 2011-07-21T20:01:53.140 回答
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

于 2014-06-14T17:58:07.643 回答