参数说明

参数 说明
LOW_PRIORITY 如果指定了 LOW_PRIORITY,删除操作将延迟到没有进程从表中读取数据时执行
IGNORE 如果指定了 IGNORE,删除过程中遇到的所有错误将被忽略
table 要从中删除记录的表
WHERE conditions 必须满足的条件,满足条件的记录才会被删除。如果未提供条件,则表中的所有记录都将被删除
ORDER BY expression 如果指定了 ORDER BY,将按给定的顺序删除记录
LIMIT 控制要从表中删除的最大记录数。将删除指定的行数

第 11.1 节:多表删除

MySQL 的 DELETE 语句可以使用 JOIN 结构,也允许指定要从哪些表中删除。这对于避免嵌套查询很有用。给定以下模式:

CREATE TABLE people (
    id INT PRIMARY KEY,
    name VARCHAR(100) NOT NULL,
    gender CHAR(1) NOT NULL
);

INSERT INTO people (id, name, gender) VALUES
(1, 'Kathy', 'f'),
(2, 'John', 'm'),
(3, 'Paul', 'm'),
(4, 'Kim', 'f');

CREATE TABLE pets (
    id INT AUTO_INCREMENT PRIMARY KEY,
    ownerId INT NOT NULL,
    name VARCHAR(100) NOT NULL,
    color VARCHAR(100) NOT NULL
);

INSERT INTO pets (ownerId, name, color) VALUES
(1, 'Rover', 'beige'),
(2, 'Bubbles', 'purple'),
(3, 'Spot', 'black and white'),
(1, 'Rover2', 'white');

people 表内容:

id name gender
1 Kathy f
2 John m
3 Paul m
4 Kim f

pets 表内容:

id ownerId name color
1 1 Rover beige
2 2 Bubbles purple
3 3 Spot black and white
4 1 Rover2 white

如果我们想删除 Paul 的宠物,下面的语句:

DELETE p2
FROM pets p2
WHERE p2.ownerId IN (SELECT p1.id FROM people p1 WHERE p1.name = 'Paul');

可以重写为:

DELETE p2  -- 只从 pets 表中删除行
FROM people p1
JOIN pets p2 ON p2.ownerId = p1.id
WHERE p1.name = 'Paul';

结果:1 行受影响,Spot 从 pets 中删除。

p1 和 p2 是表名的别名,对于长表名和提高可读性特别有用。

要同时删除人和宠物:

DELETE p1, p2  -- 从两个表中删除行
FROM people p1
JOIN pets p2 ON p2.ownerId = p1.id
WHERE p1.name = 'Paul';

结果:2 行受影响,Spot 从 pets 删除,Paul 从 people 删除。

外键约束

当 DELETE 语句涉及具有外键约束的表时,优化器处理表的顺序可能与关系不符。例如,向 pets 表添加外键:

ALTER TABLE pets ADD CONSTRAINT fk_pets_2_people
FOREIGN KEY (ownerId) REFERENCES people(id) ON DELETE CASCADE;

此时,引擎可能会尝试先从 people 表中删除记录,然后才处理 pets 表,从而导致以下错误:

ERROR 1451 (23000): Cannot delete or update a parent row: a foreign key constraint fails

此问题的解决方案是从 people 表中删除行,并依赖 InnoDB 的 ON DELETE CASCADE 功能来传播删除:

DELETE FROM people WHERE name = 'Paul';

结果:2 行受影响,Paul 从 people 删除,Spot 通过级联从 pets 删除。

另一种解决方案是临时禁用外键检查:

SET foreign_key_checks = 0;
DELETE p1, p2
FROM people p1
JOIN pets p2 ON p2.ownerId = p1.id
WHERE p1.name = 'Paul';
SET foreign_key_checks = 1;

第 11.2 节:DELETE 与 TRUNCATE

TRUNCATE TABLE tableName;

这将删除所有数据并重置 AUTO_INCREMENT 索引。在大型数据集上,它比 DELETE FROM tableName 快得多。在开发/测试期间非常有用。

当你 truncate 一个表时,SQL 服务器实际上并没有删除数据,而是删除表并重新创建它,从而释放页(deallocating the pages),因此在页被覆盖之前有机会恢复被 truncate 的数据。(对于 innodb_file_per_table=OFF 的情况,空间不能立即被回收。)

第 11.3 节:多表 DELETE(再次说明)

MySQL 允许指定匹配的行要从哪个表中删除。

  • 只删除员工:
DELETE e
FROM Employees e
JOIN Department d ON e.department_id = d.department_id
WHERE d.name = 'Sales';
  • 删除员工和部门:
DELETE e, d
FROM Employees e
JOIN Department d ON e.department_id = d.department_id
WHERE d.name = 'Sales';
  • 从所有表中删除(此例中同上一行):
DELETE FROM Employees
USING Employees e
JOIN Department d ON e.department_id = d.department_id
WHERE d.name = 'Sales';

(注意:实际语法可能略有不同,此处保留原文意)

第 11.4 节:基本删除

DELETE FROM myTable WHERE someColumn = 'something';

WHERE 子句是可选的,但如果没有它,所有行将被删除。

第 11.5 节:带 WHERE 子句的删除

DELETE FROM table_name WHERE field_one = 'value_one';

这将删除表中所有 field_one 列的值等于 'value_one' 的行。

WHERE 子句的工作方式与 SELECT 相同,因此可以使用 >、<、<> 或 LIKE 等操作符。

注意: 在删除查询中使用条件子句(WHERE、LIKE)是必要的。如果不使用任何条件子句,表中的所有数据都将被删除。

第 11.6 节:删除表中的所有行

DELETE FROM table_name;

这将删除表中的所有内容,所有行。这是语法的最基本示例。同时也表明,DELETE 语句应该非常小心地使用,因为如果省略 WHERE 子句,可能会清空整个表。

第 11.7 节:限制删除的行数

DELETE FROM table_name WHERE field_one = 'value_one' LIMIT 1;

这类似于“带 WHERE 子句的删除”示例,但它会在删除达到限制数量后停止删除。

如果像这样限制删除的行数,请注意,它将删除符合条件的第一行。由于结果可能在没有显式排序的情况下以不确定的顺序返回,删除的可能不是你所期望的那一行。