MYSQL 忽略非空约束,将空值插入表中并且仅显示警告

问题描述 投票:0回答:2

我使用的是 MYSQL 版本 14.14 Distrib 5.7.40,适用于 Linux (x86_64)。我创建了一个包含 3 列的表,并且这些列设置了 NOT NULL 约束。然后,当我尝试将空值直接插入表中时,它会给出一个错误,指出该列不能为空。但是,如果我尝试使用 select 语句插入空值,那么 MYSQL 会插入一条新记录并且仅显示警告。在插入的记录中,我看到 MYSQL 已将 NULL 替换为空字符串。

DROP TABLE IF EXISTS table1;

DROP TABLE IF EXISTS table2;

CREATE  TABLE IF NOT EXISTS table1 (
     id INT UNSIGNED NOT NULL AUTO_INCREMENT ,
     col_1 VARCHAR(45) NOT NULL ,
     col_2 VARCHAR(45) NOT NULL ,
     PRIMARY KEY (id));
     
CREATE TABLE IF NOT EXISTS table2 LIKE table1;

-- gets inserted as expected
INSERT INTO table1(id, col_1, col_2) VALUES (1,'aaa', 'bbb');
INSERT INTO table2(id, col_1, col_2) VALUES (2,'ccc', 'ddd');

-- does not get inserted as expected
INSERT INTO table1(col_1, col_2) VALUES ('xxx', NULL); -- ERROR 1048 (23000): Column 'col_2' cannot be null

-- gets inserted which I didn't expect, it gives a warning but inserts
INSERT INTO table1(id, col_1, col_2) SELECT id, col_1, NULL FROM table2 where id=2; -- Query OK, 1 row affected, 1 warning (0.07 sec)

我尝试在查询执行后显示警告。它说:“警告 | 1048 | 列‘col_2’不能”。但 MYSQL 仍然没有阻止我向表中插入值,它替换了空字符串。

mysql> show warnings;
+---------+------+-------------------------------+
| Level   | Code | Message                       |
+---------+------+-------------------------------+
| Warning | 1048 | Column 'col_2' cannot be null |
+---------+------+-------------------------------+
1 row in set (0.00 sec)

mysql> select * from table1;
+----+-------+-------+
| id | col_1 | col_2 |
+----+-------+-------+
|  1 | aaa   | bbb   |
|  2 | ccc   |       |
+----+-------+-------+
2 rows in set (0.01 sec)
mysql sql constraints mysql-cli
2个回答
1
投票

我为什么要回答自己的问题?我有这个问题并发现类似的问题。答案简要地向我指出了 SQL 严格模式。但没有一个答案是全面的,所以我不得不自己挖掘。我已经了解了 MYSQL NOT NULL CONSTRAINT 和 SQL STRICT MODE 如何一起工作,我想在这里详细说明我的答案。

首先让我们了解,当我们尝试将 NULL 值插入具有 NOT NULL 约束的列时会发生什么。

table1 有三列 id、col_1 和 col_2,它们都有 NOT NULL 约束

mysql> desc table1;
+-------+------------------+------+-----+---------+----------------+
| Field | Type             | Null | Key | Default | Extra          |
+-------+------------------+------+-----+---------+----------------+
| id    | int(10) unsigned | NO   | PRI | NULL    | auto_increment |
| col_1 | varchar(45)      | NO   |     | NULL    |                |
| col_2 | varchar(45)      | NO   |     | NULL    |                |
+-------+------------------+------+-----+---------+----------------+
3 rows in set (0.03 sec)

当我们尝试向列中插入显式 NULL 值时,MYSQL 会抛出错误。

mysql> insert into table1(col_1, col_2) values (NULL,'xxx');
ERROR 1048 (23000): Column 'col_1' cannot be null

但是,如果我们尝试跳过某一列(而不是插入值),MYSQL 不会给出错误。相反,它会插入记录并仅发出警告。

mysql> insert into table1(col_2) values ('xxx');
Query OK, 1 row affected, 1 warning (0.10 sec)

mysql> show warnings;
+---------+------+--------------------------------------------+
| Level   | Code | Message                                    |
+---------+------+--------------------------------------------+
| Warning | 1364 | Field 'col_1' doesnt have a default value |
+---------+------+--------------------------------------------+
1 row in set (0.00 sec)

mysql> select * from table1;
+----+-------+-------+
| id | col_1 | col_2 |
+----+-------+-------+
|  4 |       | xxx   |
+----+-------+-------+
1 row in set (0.00 sec)

我们还可以使用选择查询将值插入表中。在这种情况下,MYSQL 再次只给出警告并插入记录。

mysql> insert into table1(col_1, col_2) select NULL, col_2 from table2;
Query OK, 1 row affected, 1 warning (0.07 sec)
Records: 1  Duplicates: 0  Warnings: 1

mysql> show warnings;
+---------+------+-------------------------------+
| Level   | Code | Message                       |
+---------+------+-------------------------------+
| Warning | 1048 | Column 'col_1' cannot be null |
+---------+------+-------------------------------+
1 row in set (0.00 sec)

mysql> select * from table1;
+----+-------+-------+
| id | col_1 | col_2 |
+----+-------+-------+
|  4 |       | xxx   |
|  5 |       | ddd   |
+----+-------+-------+
2 rows in set (0.00 sec)

现在让我们了解一下MYSQL中的SQL模式。严格模式控制 MySQL 如何处理数据更改语句(例如 INSERT 或 UPDATE)中的无效值或缺失值。详情请参阅 MYSQL 文档

要检查当前的 SQL 模式,请尝试以下操作。

mysql> select @@sql_mode;
+----------------------------------------------------------------------------------------------------+
| @@sql_mode                                                                                         |
+----------------------------------------------------------------------------------------------------+
| NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION |
+----------------------------------------------------------------------------------------------------+
1 row in set (0.04 sec)

要将 MYSQL 设置为严格模式,请尝试以下操作。

mysql> set sql_mode='STRICT_ALL_TABLES';
Query OK, 0 rows affected, 1 warning (0.00 sec)

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

当 MYSQL 设置为严格模式后,如果您尝试之前的插入语句,它们会失败并出现错误。

mysql> insert into table1(col_2) values ('xxx');
ERROR 1364 (HY000): Field 'col_1' doesnt have a default value
mysql> insert into table1(col_1, col_2) select NULL, col_2 from table2;
ERROR 1048 (23000): Column 'col_1' cannot be null

还有一件事是,SQL_MODE 只会为当前 MYSQL 会话设置。如果你想永久设置它,那么你必须在 GLOBAL 或 MYSQL 配置文件中设置它。

尝试以下操作将严格模式设置为全局 SQL 模式。

mysql> set global sql_mode='STRICT_ALL_TABLES';
Query OK, 0 rows affected, 1 warning (0.01 sec)

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

我希望这个很长的答案能够对 SQL 模式和 MYSQL 中的插入有所帮助。如果您觉得问题和答案有帮助,请投票。


0
投票

我也面临类似类型的错误,我正在更新仅包含一个属性的城市表(name:string、allowNull:false、unique:true)。我正在使用express来构建后端服务器并使用sequelize orm来更新mysql数据库中的城市表。 我正在使用补丁请求来更新城市表,当我发送带有空字符串的请求时,它所做的就是用空字符串更新城市表。这里mysql应该抛出一个错误,因为城市表中的名称属性不允许有空值,我也希望发生这种情况,但令我惊讶的是它没有抛出错误而是用空字符串更新名称字段。 任何人都可以建议什么可能是错误的或者我可以做什么来解决这个问题?

此外,通过引入 validateRequest 中间件,我能够捕获这个空字符串值,但是当我类似地实现一个以 modelNumber 和容量作为列的飞机模型时,它抛出了非空错误。 所以,我对此有点困惑。

© www.soinside.com 2019 - 2024. All rights reserved.