“MySQL 语句:数据处理语句(DML)”的版本间差异
跳到导航
跳到搜索
第63行: | 第63行: | ||
== DELETE 语句 == | == DELETE 语句 == | ||
# 单表语法: | |||
#: <syntaxhighlight lang="mysql"> | |||
DELETE [LOW_PRIORITY] [QUICK] [IGNORE] FROM tbl_name | |||
[PARTITION (partition_name [, partition_name] ...)] | |||
[WHERE where_condition] | |||
[ORDER BY ...] | |||
[LIMIT row_count] | |||
</syntaxhighlight> | |||
#* DELETE语句从 tbl_name 中删除行,并返回删除的行数。要检查已删除的行数,请调用“'''ROW_COUNT()'''”函数。 | |||
# 主要子句: | |||
## “WHERE”子句:where_condition 是一个表达式,对于要删除的每一行,其值为 true; | |||
## “ORDER BY”子句,则按指定的 Sequences 删除行; | |||
## “LIMIT”子句:限制了可以删除的行数。 | |||
#* (这些子句适用于单表删除,但不适用于多表删除) | |||
# 多表语法: | |||
#: <syntaxhighlight lang="mysql"> | |||
DELETE [LOW_PRIORITY] [QUICK] [IGNORE] | |||
tbl_name[.*] [, tbl_name[.*]] ... | |||
FROM table_references | |||
[WHERE where_condition] | |||
DELETE [LOW_PRIORITY] [QUICK] [IGNORE] | |||
FROM tbl_name[.*] [, tbl_name[.*]] ... | |||
USING table_references | |||
[WHERE where_condition] | |||
</syntaxhighlight> | |||
# 权限: | |||
#: 需要对表具有 DELETE 权限才能从中删除行。对于仅读取的任何列,例如 WHERE 子句中命名的列,只需要 SELECT 特权。 | |||
# 性能: | |||
#* 当不需要知道已删除的行数时,与没有 WHERE 子句的 DELETE 语句相比,“'''TRUNCATE TABLE'''”语句是清空表的更快方法。【见:'''“[http://wiki.eijux.com/MySQL_%E8%AF%AD%E5%8F%A5%EF%BC%9A%E6%95%B0%E6%8D%AE%E5%AE%9A%E4%B9%89%E8%AF%AD%E5%8F%A5%EF%BC%88DDL%EF%BC%89#TRUNCATE_TABLE_.E8.AF.AD.E5.8F.A5 TRUNCATE TABLE 语句]”'''】 | |||
#** 与DELETE不同,TRUNCATE TABLE不能在事务内使用或在表上有锁时不能使用。 | |||
#* 为了确保给定的 DELETE 语句不会花费太多时间,针对 DELETE 的特定于 MySQL 的“LIMIT row_count”子句指定了要删除的最大行数。如果要删除的行数大于限制,请重复 DELETE 语句,直到受影响的行数小于 LIMIT 值。【?】 | |||
# 子查询: | |||
#: 您不能从 table 中删除,也不能从子查询的同一 table 中选择。 | |||
# 分区表支持: | |||
#: DELETE 使用“PARTITION”选项支持显式分区选择,该选项采用一个或多个分区或子分区(或两者)的逗号分隔名称列表,从中选择要删除的行。【未包括在列 table 中的分区将被忽略】 | |||
#:: 给定具有名为 p0 的分区的分区表 t,执行语句“'''DELETE FROM t PARTITION (p0)'''”与执行“'''ALTER TABLE t TRUNCATE PARTITION (p0)'''”具有相同的作用;在这两种情况下,都将删除分区 p0 中的所有行。 | |||
#* PARTITION 可以与 WHERE 条件一起使用,在这种情况下,仅在列出的分区中的行上测试该条件。 | |||
#* PARTITION 选项也可以在多表 DELETE 语句中使用。在 FROM 选项中命名的表中,最多可以使用一个这样的选项。 | |||
# 自动递增列: | |||
## 如果删除包含“AUTO_INCREMENT”列最大值的行,则该值不会再用于 MyISAM 或 InnoDB 表。 | |||
## 如果在 autocommit 模式下使用“DELETE FROM tbl_name”(不带WHERE子句)删除 table 中的所有行,则该序列将从 InnoDB 和 MyISAM 以外的所有存储引擎重新开始。 | |||
## 对于 MyISAM 表,可以在多列键中指定 AUTO_INCREMENT 个辅助列。在这种情况下,即使对于 MyISAM 表,也会重复使用从序列顶部删除的值。 | |||
# 修饰符: | |||
#: DELETE语句支持以下修饰符: | |||
## 如果指定“'''LOW_PRIORITY'''”修饰符,则服务器将延迟 DELETE 的执行,直到没有其他 Client 端从 table 中读取。 | |||
##* 这仅影响仅使用 table 级锁定(例如 MyISAM,MEMORY 和 MERGE)的存储引擎。 | |||
## 对于 MyISAM 表,如果使用“'''QUICK'''”修饰符,则存储引擎在删除期间不会合并索引叶,这可能会加快某些类型的删除操作。 | |||
## “'''IGNORE'''”修饰符使 MySQL 在删除行的过程中忽略错误。(在解析阶段遇到的错误将以通常的方式处理)由于使用 IGNORE 而被忽略的错误将作为警告返回。 | |||
# 删除顺序: | |||
#: 如果 DELETE 语句包含“ORDER BY”子句,则按该子句指定的 Sequences 删除行。【这主要与“LIMIT”结合使用】 | |||
#: 示例:查找与 WHERE 子句匹配的行,按 timestamp_column 对其进行排序,并删除第一个(最旧的)行: | |||
#: <syntaxhighlight lang="mysql"> | |||
DELETE FROM somelog WHERE user = 'jcole' | |||
ORDER BY timestamp_column LIMIT 1; | |||
</syntaxhighlight> | |||
#* ORDER BY 还有助于按照避免引用完整性违规的 Sequences 删除行。 | |||
# InnoDB 表: | |||
#: 如果要从大 table 中删除许多行,则可能会超出 InnoDB 表的锁定表大小。为了避免此问题,或者只是为了最小化表保持锁定的时间,以下策略(根本不使用 DELETE)可能会有所帮助: | |||
## 将未被删除的行插入到与原始表具有相同结构的空表中: | |||
##: <syntaxhighlight lang="mysql"> | |||
INSERT INTO t_copy SELECT * FROM t WHERE ... ; | |||
</syntaxhighlight> | |||
## 使用“RENAME TABLE”(原子操作):将原始表移开,并将副本重命名为原始名称: | |||
##: <syntaxhighlight lang="mysql"> | |||
RENAME TABLE t TO t_old, t_copy TO t; | |||
</syntaxhighlight> | |||
## 删除原始表: | |||
##: <syntaxhighlight lang="mysql"> | |||
DROP TABLE t_old; | |||
</syntaxhighlight> | |||
#* RENAME TABLE 执行时,没有其他会话可以访问涉及的表,因此重命名操作不会出现并发问题。 | |||
# MyISAM 表:【???】 | |||
#: 在 MyISAM 表中,删除的行保留在链接列表中,随后的 INSERT 操作重用旧的行位置。要回收未使用的空间并减小文件大小,请使用“OPTIMIZE TABLE”语句或“myisamchk”Util 重新组织表。 | |||
#* 【OPTIMIZE TABLE更易于使用,但myisamchk更快】 | |||
#: “QUICK”修饰符影响索引叶是否合并以进行删除操作。“DELETE QUICK”对于将删除行的索引值替换为以后插入的行的相似索引值的应用程序最有用。在这种情况下,删除值留下的漏洞将被重用。【?】 | |||
#: 当删除的值导致索引块填充不足,该索引块跨越索引值范围而又发生新插入时,“DELETE QUICK”无效。在这种情况下,使用“QUICK”会导致索引中浪费空间而无法回收。这是这种情况的示例: | |||
## 创建一个包含索引的 AUTO_INCREMENT 列的表。 | |||
## 在表中插入许多行。每次插入都会产生一个索引值,该值将添加到索引的高端。 | |||
## 使用“DELETE QUICK”删除列范围低端的行块。 | |||
#: 在这种情况下,与已删除索引值关联的索引块将被填充不足,但由于使用QUICK而不会与其他索引块合并。当发生新的插入操作时,它们仍会填充不足,因为新行的索引值不在删除范围内。此外,即使您以后使用DELETE而不使用QUICK,它们仍会填充不足,除非某些已删除的索引值恰好位于填充不足的块内或邻近的索引块中。要在这种情况下回收未使用的索引空间,请使用OPTIMIZE TABLE。 | |||
#* 如果要从 table 中删除许多行,使用 DELETE QUICK 后跟 OPTIMIZE TABLE 可能会更快。这将重建索引,而不是执行许多索引块合并操作。 | |||
# 多表删除: | |||
#: 您可以在 DELETE 语句中指定多个表,以根据 WHERE 子句中的条件从一个或多个表中删除行。 | |||
#* 不能在多表 DELETE 中使用 ORDER BY 或 LIMIT。 | |||
## 仅删除表中 FROM 子句前列出的“列”的匹配行: | |||
##: <syntaxhighlight lang="mysql"> | |||
DELETE t1, t2 FROM t1 INNER JOIN t2 INNER JOIN t3 | |||
WHERE t1.id=t2.id AND t2.id=t3.id; | |||
</syntaxhighlight> | |||
## 仅删除 FROM 子句中列出的“表”中匹配的行(在 USING 子句之前): | |||
##* (同时从许多 table 中删除行,并使其他 table 仅用于搜索) | |||
##: <syntaxhighlight lang="mysql"> | |||
DELETE FROM t1, t2 USING t1 INNER JOIN t2 INNER JOIN t3 | |||
WHERE t1.id=t2.id AND t2.id=t3.id; | |||
</syntaxhighlight> | |||
#* 如果您使用涉及外键约束的 InnoDB 表的多表 DELETE 语句,则 MySQL 优化器可能以与其父/子关系不同的 Sequences 处理表。在这种情况下,该语句将失败并回滚。相反,您应该从单个表中删除,并依靠 InnoDB 提供的“ON DELETE”功能来相应地修改其他表。 | |||
#* 关于使用别名: | |||
#*: Correct: | |||
#*: <syntaxhighlight lang="mysql"> | |||
DELETE a1, a2 FROM t1 AS a1 INNER JOIN t2 AS a2 | |||
WHERE a1.id=a2.id; | |||
DELETE FROM a1, a2 USING t1 AS a1 INNER JOIN t2 AS a2 | |||
WHERE a1.id=a2.id; | |||
</syntaxhighlight> | |||
#*: Incorrect: | |||
#*: <syntaxhighlight lang="mysql"> | |||
DELETE t1 AS a1, t2 AS a2 FROM t1 INNER JOIN t2 | |||
WHERE a1.id=a2.id; | |||
DELETE FROM t1 AS a1, t2 AS a2 USING t1 INNER JOIN t2 | |||
WHERE a1.id=a2.id; | |||
</syntaxhighlight> | |||
== DO 语句 == | == DO 语句 == |
2021年4月11日 (日) 20:18的版本
关于
CALL 语句
CALL sp_name([parameter[,...]])
CALL sp_name[()]
- CALL语句调用先前用“CREATE PROCEDURE”定义的存储过程。
- 可以不带括号地调用不带参数的存储过程。也就是说,“CALL p()”和“CALL p”是等效的。
- 【见:“CREATE PROCEDURE 和 CREATE FUNCTION 语句”】
CALL可以使用声明为OUT或INOUT参数的参数将值传递回其调用方。当过程返回时,Client 端程序也可以获得在例程中执行的最终语句所影响的行数:在 SQL 级别,调用“ROW_COUNT()”函数;从 C API 中,调用“mysql_affected_rows()”函数。
- 对于“INOUT”参数,在将其值传递给过程之前对其进行初始化。
- 在与“PREPARE”和“EXECUTE”一起使用的已准备好的 CALL 语句中,占位符可用于 IN 参数,OUT 和 INOUT 参数。
示例:以下过程具有一个 OUT 参数,该参数将该过程设置为当前服务器版本,以及一个 INOUT 值,该过程从其当前值开始加一:
CREATE PROCEDURE p (OUT ver_param VARCHAR(25), INOUT incr_param INT)
BEGIN
# Set value of OUT parameter
SELECT VERSION() INTO ver_param;
# Increment value of INOUT parameter
SET incr_param = incr_param + 1;
END;
在调用该过程之前,初始化要作为INOUT参数传递的变量。调用该过程后,将设置或修改两个变量的值:
mysql> SET @increment = 10;
mysql> CALL p(@version, @increment);
mysql> SELECT @version, @increment;
+------------------+------------+
| @version | @increment |
+------------------+------------+
| 5.7.20-debug-log | 11 |
+------------------+------------+
示例:在与 PREPARE 和 EXECUTE 一起使用的已准备好的 CALL 语句中,占位符可用于 IN 参数,OUT 和 INOUT 参数。这些类型的参数可以按如下方式使用:
mysql> SET @increment = 10;
mysql> PREPARE s FROM 'CALL p(?, ?)';
mysql> EXECUTE s USING @version, @increment;
mysql> SELECT @version, @increment;
+------------------+------------+
| @version | @increment |
+------------------+------------+
| 5.7.20-debug-log | 11 |
+------------------+------------+
- 关于“CLIENT_MULTI_RESULTS”:【???】
- 要编写使用CALL SQL 语句执行生成结果集的存储过程的 C 程序,必须启用“CLIENT_MULTI_RESULTS”标志。这是因为,除了过程中执行的语句可能返回的任何结果集之外,每个 CALL 还会返回指示呼叫状态的结果。如果将 CALL 用于执行任何包含准备好的语句的存储过程,则也必须启用“CLIENT_MULTI_RESULTS”。无法确定何时加载此类过程是否会产生这些语句,因此有必要假设它们会产生结果。
- 可以在调用“mysql_real_connect()”时启用“CLIENT_MULTI_RESULTS”,或者通过传递“CLIENT_MULTI_RESULTS”标志本身来显式,或者通过“CLIENT_MULTI_RESULTS”隐式传递(也将启用“CLIENT_MULTI_RESULTS”)。 “CLIENT_MULTI_RESULTS”默认启用。
- 要处理使用“mysql_query()”或“mysql_real_query()”执行的 CALL 语句的结果,请使用调用“mysql_next_result()”的循环来确定是否还有更多结果。【???】
- C 程序可以使用 Prepared-Statement 接口执行 CALL 语句并访问 OUT 和 INOUT 参数。这是通过使用调用“mysql_stmt_next_result()”的循环以确定是否还有更多结果来处理CALL语句的结果来完成的。【???】
DELETE 语句
- 单表语法:
DELETE [LOW_PRIORITY] [QUICK] [IGNORE] FROM tbl_name [PARTITION (partition_name [, partition_name] ...)] [WHERE where_condition] [ORDER BY ...] [LIMIT row_count]
- DELETE语句从 tbl_name 中删除行,并返回删除的行数。要检查已删除的行数,请调用“ROW_COUNT()”函数。
- 主要子句:
- “WHERE”子句:where_condition 是一个表达式,对于要删除的每一行,其值为 true;
- “ORDER BY”子句,则按指定的 Sequences 删除行;
- “LIMIT”子句:限制了可以删除的行数。
- (这些子句适用于单表删除,但不适用于多表删除)
- 多表语法:
DELETE [LOW_PRIORITY] [QUICK] [IGNORE] tbl_name[.*] [, tbl_name[.*]] ... FROM table_references [WHERE where_condition] DELETE [LOW_PRIORITY] [QUICK] [IGNORE] FROM tbl_name[.*] [, tbl_name[.*]] ... USING table_references [WHERE where_condition]
- 权限:
- 需要对表具有 DELETE 权限才能从中删除行。对于仅读取的任何列,例如 WHERE 子句中命名的列,只需要 SELECT 特权。
- 性能:
- 当不需要知道已删除的行数时,与没有 WHERE 子句的 DELETE 语句相比,“TRUNCATE TABLE”语句是清空表的更快方法。【见:“TRUNCATE TABLE 语句”】
- 与DELETE不同,TRUNCATE TABLE不能在事务内使用或在表上有锁时不能使用。
- 为了确保给定的 DELETE 语句不会花费太多时间,针对 DELETE 的特定于 MySQL 的“LIMIT row_count”子句指定了要删除的最大行数。如果要删除的行数大于限制,请重复 DELETE 语句,直到受影响的行数小于 LIMIT 值。【?】
- 当不需要知道已删除的行数时,与没有 WHERE 子句的 DELETE 语句相比,“TRUNCATE TABLE”语句是清空表的更快方法。【见:“TRUNCATE TABLE 语句”】
- 子查询:
- 您不能从 table 中删除,也不能从子查询的同一 table 中选择。
- 分区表支持:
- DELETE 使用“PARTITION”选项支持显式分区选择,该选项采用一个或多个分区或子分区(或两者)的逗号分隔名称列表,从中选择要删除的行。【未包括在列 table 中的分区将被忽略】
- 给定具有名为 p0 的分区的分区表 t,执行语句“DELETE FROM t PARTITION (p0)”与执行“ALTER TABLE t TRUNCATE PARTITION (p0)”具有相同的作用;在这两种情况下,都将删除分区 p0 中的所有行。
- PARTITION 可以与 WHERE 条件一起使用,在这种情况下,仅在列出的分区中的行上测试该条件。
- PARTITION 选项也可以在多表 DELETE 语句中使用。在 FROM 选项中命名的表中,最多可以使用一个这样的选项。
- DELETE 使用“PARTITION”选项支持显式分区选择,该选项采用一个或多个分区或子分区(或两者)的逗号分隔名称列表,从中选择要删除的行。【未包括在列 table 中的分区将被忽略】
- 自动递增列:
- 如果删除包含“AUTO_INCREMENT”列最大值的行,则该值不会再用于 MyISAM 或 InnoDB 表。
- 如果在 autocommit 模式下使用“DELETE FROM tbl_name”(不带WHERE子句)删除 table 中的所有行,则该序列将从 InnoDB 和 MyISAM 以外的所有存储引擎重新开始。
- 对于 MyISAM 表,可以在多列键中指定 AUTO_INCREMENT 个辅助列。在这种情况下,即使对于 MyISAM 表,也会重复使用从序列顶部删除的值。
- 修饰符:
- DELETE语句支持以下修饰符:
- 如果指定“LOW_PRIORITY”修饰符,则服务器将延迟 DELETE 的执行,直到没有其他 Client 端从 table 中读取。
- 这仅影响仅使用 table 级锁定(例如 MyISAM,MEMORY 和 MERGE)的存储引擎。
- 对于 MyISAM 表,如果使用“QUICK”修饰符,则存储引擎在删除期间不会合并索引叶,这可能会加快某些类型的删除操作。
- “IGNORE”修饰符使 MySQL 在删除行的过程中忽略错误。(在解析阶段遇到的错误将以通常的方式处理)由于使用 IGNORE 而被忽略的错误将作为警告返回。
- 删除顺序:
- 如果 DELETE 语句包含“ORDER BY”子句,则按该子句指定的 Sequences 删除行。【这主要与“LIMIT”结合使用】
- 示例:查找与 WHERE 子句匹配的行,按 timestamp_column 对其进行排序,并删除第一个(最旧的)行:
DELETE FROM somelog WHERE user = 'jcole' ORDER BY timestamp_column LIMIT 1;
- ORDER BY 还有助于按照避免引用完整性违规的 Sequences 删除行。
- InnoDB 表:
- 如果要从大 table 中删除许多行,则可能会超出 InnoDB 表的锁定表大小。为了避免此问题,或者只是为了最小化表保持锁定的时间,以下策略(根本不使用 DELETE)可能会有所帮助:
- 将未被删除的行插入到与原始表具有相同结构的空表中:
INSERT INTO t_copy SELECT * FROM t WHERE ... ;
- 使用“RENAME TABLE”(原子操作):将原始表移开,并将副本重命名为原始名称:
RENAME TABLE t TO t_old, t_copy TO t;
- 删除原始表:
DROP TABLE t_old;
- RENAME TABLE 执行时,没有其他会话可以访问涉及的表,因此重命名操作不会出现并发问题。
- MyISAM 表:【???】
- 在 MyISAM 表中,删除的行保留在链接列表中,随后的 INSERT 操作重用旧的行位置。要回收未使用的空间并减小文件大小,请使用“OPTIMIZE TABLE”语句或“myisamchk”Util 重新组织表。
- 【OPTIMIZE TABLE更易于使用,但myisamchk更快】
- “QUICK”修饰符影响索引叶是否合并以进行删除操作。“DELETE QUICK”对于将删除行的索引值替换为以后插入的行的相似索引值的应用程序最有用。在这种情况下,删除值留下的漏洞将被重用。【?】
- 当删除的值导致索引块填充不足,该索引块跨越索引值范围而又发生新插入时,“DELETE QUICK”无效。在这种情况下,使用“QUICK”会导致索引中浪费空间而无法回收。这是这种情况的示例:
- 创建一个包含索引的 AUTO_INCREMENT 列的表。
- 在表中插入许多行。每次插入都会产生一个索引值,该值将添加到索引的高端。
- 使用“DELETE QUICK”删除列范围低端的行块。
- 在这种情况下,与已删除索引值关联的索引块将被填充不足,但由于使用QUICK而不会与其他索引块合并。当发生新的插入操作时,它们仍会填充不足,因为新行的索引值不在删除范围内。此外,即使您以后使用DELETE而不使用QUICK,它们仍会填充不足,除非某些已删除的索引值恰好位于填充不足的块内或邻近的索引块中。要在这种情况下回收未使用的索引空间,请使用OPTIMIZE TABLE。
- 如果要从 table 中删除许多行,使用 DELETE QUICK 后跟 OPTIMIZE TABLE 可能会更快。这将重建索引,而不是执行许多索引块合并操作。
- 多表删除:
- 您可以在 DELETE 语句中指定多个表,以根据 WHERE 子句中的条件从一个或多个表中删除行。
- 不能在多表 DELETE 中使用 ORDER BY 或 LIMIT。
- 仅删除表中 FROM 子句前列出的“列”的匹配行:
DELETE t1, t2 FROM t1 INNER JOIN t2 INNER JOIN t3 WHERE t1.id=t2.id AND t2.id=t3.id;
- 仅删除 FROM 子句中列出的“表”中匹配的行(在 USING 子句之前):
- (同时从许多 table 中删除行,并使其他 table 仅用于搜索)
DELETE FROM t1, t2 USING t1 INNER JOIN t2 INNER JOIN t3 WHERE t1.id=t2.id AND t2.id=t3.id;
- 如果您使用涉及外键约束的 InnoDB 表的多表 DELETE 语句,则 MySQL 优化器可能以与其父/子关系不同的 Sequences 处理表。在这种情况下,该语句将失败并回滚。相反,您应该从单个表中删除,并依靠 InnoDB 提供的“ON DELETE”功能来相应地修改其他表。
- 关于使用别名:
- Correct:
DELETE a1, a2 FROM t1 AS a1 INNER JOIN t2 AS a2 WHERE a1.id=a2.id; DELETE FROM a1, a2 USING t1 AS a1 INNER JOIN t2 AS a2 WHERE a1.id=a2.id;
- Incorrect:
DELETE t1 AS a1, t2 AS a2 FROM t1 INNER JOIN t2 WHERE a1.id=a2.id; DELETE FROM t1 AS a1, t2 AS a2 USING t1 INNER JOIN t2 WHERE a1.id=a2.id;