SELECT
[ALL | DISTINCT | DISTINCTROW ]
[HIGH_PRIORITY]
[STRAIGHT_JOIN]
[SQL_SMALL_RESULT] [SQL_BIG_RESULT] [SQL_BUFFER_RESULT]
[SQL_NO_CACHE] [SQL_CALC_FOUND_ROWS]
select_expr [, select_expr] ...
[into_option]
[FROM table_references
[PARTITION partition_list]]
[WHERE where_condition]
[GROUP BY {col_name | expr | position}, ... [WITH ROLLUP]]
[HAVING where_condition]
[WINDOW window_name AS (window_spec)
[, window_name AS (window_spec)] ...]
[ORDER BY {col_name | expr | position}
[ASC | DESC], ... [WITH ROLLUP]]
[LIMIT {[offset,] row_count | row_count OFFSET offset}]
[into_option]
[FOR {UPDATE | SHARE}
[OF tbl_name [, tbl_name] ...]
[NOWAIT | SKIP LOCKED]
| LOCK IN SHARE MODE]
[into_option]
into_option: {
INTO OUTFILE 'file_name'
[CHARACTER SET charset_name]
export_options
| INTO DUMPFILE 'file_name'
| INTO var_name [, var_name] ...
}
SELECT 用于检索从一个或多个表中选择的行,并且可以包含 UNION 操作和子查询。还支持 INTERSECT 和 EXCEPT 操作。UNION、INTERSECT 和 EXCEPT 运算符将在本节后面详细介绍。另见 第 15.2.15 节“子查询”。
SELECT 语句可以以 WITH 子句开头,以定义可在 SELECT 中访问的公用表表达式。见 第 15.2.20 节“WITH (公用表表达式)”。
SELECT 语句最常用的子句如下:
每个
select_expr表示要检索的列。必须至少有一个select_expr。table_references指示从中检索行的表。其语法在第 15.2.13.2 节,“JOIN 子句”中描述。SELECT支持使用PARTITION子句进行显式分区选择,该子句后跟table_reference中表名后的分区或子分区(或两者)列表(请参阅第 15.2.13.2 节,“JOIN 子句”)。在这种情况下,仅从列出的分区中选择行,并且忽略该表的任何其他分区。有关更多信息和示例,请参阅第 26.5 节,“分区选择”。WHERE子句(如果给出)指示行必须满足才能被选中的条件。where_condition是一个表达式,对于要选择的每一行,该表达式的计算结果均为 true。如果没有WHERE子句,则该语句将选择所有行。在
WHERE表达式中,可以使用 MySQL 支持的任何函数和运算符,但聚合(分组)函数除外。请参阅第 11.5 节,“表达式”和第 14 章,*函数和运算符*。
SELECT 也可以用于检索在不参考任何表的情况下计算的行。
例如:
mysql> SELECT 1 + 1;
-> 2
在没有引用任何表的情况下,允许您将 DUAL 指定为虚拟表名。
mysql> SELECT 1 + 1 FROM DUAL;
-> 2
DUAL 纯粹是为了方便那些要求所有 SELECT 语句都应该具有 FROM 和其他子句的人。MySQL 可能会忽略这些子句。如果没有引用任何表,则 MySQL 不需要 FROM DUAL。
通常,必须严格按照语法说明中显示的顺序给出所使用的子句。例如,HAVING 子句必须出现在任何 GROUP BY 子句之后和任何 ORDER BY 子句之前。INTO 子句(如果存在)可以出现在语法说明指示的任何位置,但在给定语句中只能出现一次,而不能出现在多个位置。有关 INTO 的更多信息,请参阅第 15.2.13.1 节,“SELECT ... INTO 语句”。
select_expr 项的列表包含选择列表,该列表指示要检索哪些列。术语指定一个列或表达式,或者可以使用 *-速记。
仅包含单个非限定
*的选择列表可以用作速记,以选择所有表中的所有列。SELECT * FROM t1 INNER JOIN t2 ...可以用作限定速记,以选择命名表中的所有列。tbl_name.*SELECT t1.*, t2.* FROM t1 INNER JOIN t2 ...如果表具有不可见列,则
*和不包含它们。要包含不可见列,必须显式引用它们。tbl_name.*在选择列表中的其他项中使用非限定
*可能会产生解析错误。例如:SELECT id, * FROM t1为避免此问题,请使用限定的
引用。tbl_name.*SELECT id, t1.* FROM t1对选择列表中的每个表使用限定的
引用。tbl_name.*SELECT AVG(score), t1.* FROM t1 ...
以下列表提供了有关其他 SELECT 子句的更多信息。
可以使用
AS为alias_nameselect_expr指定别名。该别名用作表达式的列名,并且可以在GROUP BY、ORDER BY或HAVING子句中使用。例如:SELECT CONCAT(last_name,', ',first_name) AS full_name FROM mytable ORDER BY full_name;使用标识符为
select_expr指定别名时,AS关键字是可选的。前面的示例可以写成如下形式:SELECT CONCAT(last_name,', ',first_name) full_name FROM mytable ORDER BY full_name;但是,由于
AS是可选的,因此如果忘记了两个select_expr表达式之间的逗号,则可能会出现一个微妙的问题:MySQL 会将第二个表达式解释为别名。例如,在以下语句中,columnb被视为别名。SELECT columna columnb FROM mytable;因此,最好养成在指定列别名时显式使用
AS的习惯。不允许在
WHERE子句中引用列别名,因为在执行WHERE子句时可能尚未确定列值。请参阅第 B.3.4.4 节,“列别名问题”。FROM子句指示要从中检索行的表。如果指定了多个表,则表示您正在执行联接。有关联接语法的更多信息,请参阅第 15.2.13.2 节,“JOIN 子句”。对于指定的每个表,您都可以选择指定一个别名。table_referencestbl_name [[AS] alias] [index_hint]索引提示的使用为优化器提供了有关如何在查询处理期间选择索引的信息。有关指定这些提示的语法说明,请参阅第 10.9.4 节,“索引提示”。
您可以使用
SET max_seeks_for_key=作为强制 MySQL 首选键扫描而不是表扫描的另一种方法。请参阅第 7.1.8 节,“服务器系统变量”。value您可以将默认数据库中的表称为
tbl_name,也可以称为db_name.tbl_name以显式指定数据库。您可以将列称为col_name、tbl_name.col_name或db_name.tbl_name.col_name。除非引用不明确,否则不需要为列引用指定tbl_name或db_name.tbl_name前缀。有关需要更明确的列引用形式的歧义示例,请参阅第 11.2.2 节,“标识符限定符”。可以使用
或tbl_nameASalias_nametbl_name alias_name为表引用指定别名。以下语句是等效的。SELECT t1.name, t2.salary FROM employee AS t1, info AS t2 WHERE t1.name = t2.name; SELECT t1.name, t2.salary FROM employee t1, info t2 WHERE t1.name = t2.name;可以使用列名、列别名或列位置在
ORDER BY和GROUP BY子句中引用为输出选择的列。列位置是整数,从 1 开始。SELECT college, region, seed FROM tournament ORDER BY region, seed; SELECT college, region AS r, seed AS s FROM tournament ORDER BY r, s; SELECT college, region, seed FROM tournament ORDER BY 2, 3;要按降序排序,请将
DESC(降序)关键字添加到ORDER BY子句中要排序的列的名称中。默认值为升序;可以使用ASC关键字显式指定。如果
ORDER BY出现在带括号的查询表达式中,并且也应用于外部查询,则结果是不确定的,并且在未来版本的 MySQL 中可能会更改。不建议使用列位置,因为该语法已从 SQL 标准中删除。
当您使用
ORDER BY或GROUP BY对SELECT中的列进行排序时,服务器仅使用max_sort_length系统变量指示的初始字节数对值进行排序。MySQL 扩展了
GROUP BY的使用,以允许选择GROUP BY子句中未提及的字段。如果您没有从查询中获得预期的结果,请阅读第 14.19 节,“聚合函数”中对GROUP BY的说明。HAVING子句与WHERE子句类似,用于指定选择条件。WHERE子句指定选择列表中列的条件,但不能引用聚合函数。HAVING子句指定组的条件,通常由GROUP BY子句形成。查询结果仅包含满足HAVING条件的组。(如果没有GROUP BY,则所有行都隐式地形成一个聚合组。)HAVING子句几乎是最后应用的,就在将项发送到客户端之前,并且没有优化。(LIMIT在HAVING之后应用。)SQL 标准要求
HAVING必须仅引用GROUP BY子句中的列或聚合函数中使用的列。但是,MySQL 支持对这种行为的扩展,并允许HAVING引用SELECT列表中的列以及外部子查询中的列。如果
HAVING子句引用了不明确的列,则会发出警告。在以下语句中,col2是不明确的,因为它同时用作别名和列名。SELECT COUNT(col1) AS col2 FROM t GROUP BY col2 HAVING col2 = 2;优先考虑标准 SQL 行为,因此,如果
HAVING列名在GROUP BY中和选择列列表中的别名列中都使用,则优先考虑GROUP BY列中的列。不要将
HAVING用于应该出现在WHERE子句中的项。例如,不要编写以下内容:SELECT col_name FROM tbl_name HAVING col_name > 0;而应编写以下内容:
SELECT col_name FROM tbl_name WHERE col_name > 0;HAVING子句可以引用聚合函数,而WHERE子句则不能。SELECT user, MAX(salary) FROM users GROUP BY user HAVING MAX(salary) > 10;(这在某些旧版本的 MySQL 中不起作用。)
MySQL 允许重复的列名。也就是说,可以有多个具有相同名称的
select_expr。这是对标准 SQL 的扩展。由于 MySQL 还允许GROUP BY和HAVING引用select_expr值,因此这可能会导致歧义。SELECT 12 AS a, a FROM t GROUP BY a;在该语句中,两列的名称均为
a。为确保使用正确的列进行分组,请为每个select_expr使用不同的名称。WINDOW子句(如果存在)定义窗口函数可以引用的命名窗口。有关详细信息,请参阅第 14.20.4 节,“命名窗口”。MySQL 通过在
select_expr值中搜索,然后在FROM子句中表的列中搜索,来解析ORDER BY子句中非限定的列或别名引用。对于GROUP BY或HAVING子句,它会在搜索select_expr值之前先搜索FROM子句。(对于GROUP BY和HAVING,这与 MySQL 5.0 之前的行为不同,后者使用与ORDER BY相同的规则。)LIMIT子句可用于限制SELECT语句返回的行数。LIMIT接受一个或两个数字参数,这两个参数都必须是非负整数常量,但以下情况除外:在预处理语句中,可以使用
?占位符标记指定LIMIT参数。在存储程序中,可以使用整数值例程参数或局部变量指定
LIMIT参数。
使用两个参数时,第一个参数指定要返回的第一行的偏移量,第二个参数指定要返回的最大行数。初始行的偏移量为 0(而不是 1)
SELECT * FROM tbl LIMIT 5,10; # Retrieve rows 6-15要检索从某个偏移量到结果集末尾的所有行,可以对第二个参数使用某个较大的数字。此语句检索从第 96 行到最后一行的所有行
SELECT * FROM tbl LIMIT 95,18446744073709551615;使用一个参数时,该值指定要从结果集开头返回的行数
SELECT * FROM tbl LIMIT 5; # Retrieve first 5 rows换句话说,
LIMIT等效于row_countLIMIT 0,。row_count对于预处理语句,可以使用占位符。以下语句从
tbl表返回一行SET @a=1; PREPARE STMT FROM 'SELECT * FROM tbl LIMIT ?'; EXECUTE STMT USING @a;以下语句从
tbl表返回第二到第六行SET @skip=1; SET @numrows=5; PREPARE STMT FROM 'SELECT * FROM tbl LIMIT ?, ?'; EXECUTE STMT USING @skip, @numrows;为了与 PostgreSQL 兼容,MySQL 也支持
LIMIT语法。row_countOFFSEToffset如果
LIMIT出现在带括号的查询表达式中,并且也应用于外部查询,则结果未定义,并且在未来版本的 MySQL 中可能会更改。SELECT ... INTO形式的SELECT使查询结果可以写入文件或存储在变量中。有关更多信息,请参阅 第 15.2.13.1 节,“SELECT ... INTO 语句”。如果将
FOR UPDATE与使用页面锁或行锁的存储引擎一起使用,则查询检查的行将被写锁定,直到当前事务结束。不能在诸如
CREATE TABLE的语句中将new_tableSELECT ... FROMold_table...FOR UPDATE用作SELECT的一部分。(如果尝试这样做,该语句将被拒绝,并显示错误 创建“new_table”时无法更新表“old_table”。)FOR SHARE和LOCK IN SHARE MODE设置共享锁,允许其他事务读取检查的行,但不能更新或删除它们。FOR SHARE和LOCK IN SHARE MODE是等效的。但是,与FOR UPDATE一样,FOR SHARE也支持NOWAIT、SKIP LOCKED和OF选项。tbl_nameFOR SHARE是LOCK IN SHARE MODE的替代品,但为了向后兼容,LOCK IN SHARE MODE仍然可用。NOWAIT会导致FOR UPDATE或FOR SHARE查询立即执行,如果由于另一个事务持有的锁而无法获取行锁,则返回错误。SKIP LOCKED会导致FOR UPDATE或FOR SHARE查询立即执行,从结果集中排除被另一个事务锁定的行。NOWAIT和SKIP LOCKED选项对于基于语句的复制来说是不安全的。注意跳过锁定行的查询返回的数据视图不一致。因此,
SKIP LOCKED不适合一般的交易工作。但是,当多个会话访问同一个类似队列的表时,可以使用它来避免锁争用。OF将tbl_nameFOR UPDATE和FOR SHARE查询应用于命名的表。例如SELECT * FROM t1, t2 FOR SHARE OF t1 FOR UPDATE OF t2;当省略
OF时,查询块引用的所有表都将被锁定。因此,将不带tbl_nameOF的锁定子句与另一个锁定子句一起使用将返回错误。在多个锁定子句中指定同一个表将返回错误。如果在tbl_nameSELECT语句中将别名指定为表名,则锁定子句只能使用该别名。如果SELECT语句没有显式指定别名,则锁定子句只能指定实际的表名。有关
FOR UPDATE和FOR SHARE的更多信息,请参阅 第 17.7.2.4 节,“锁定读取”。有关NOWAIT和SKIP LOCKED选项的更多信息,请参阅 使用 NOWAIT 和 SKIP LOCKED 锁定读取并发。
在 SELECT 关键字之后,可以使用许多修饰符来影响语句的操作。HIGH_PRIORITY、STRAIGHT_JOIN 以及以 SQL_ 开头的修饰符是 MySQL 对标准 SQL 的扩展。
ALL和DISTINCT修饰符指定是否应返回重复行。ALL(默认值)指定应返回所有匹配的行,包括重复行。DISTINCT指定从结果集中删除重复行。同时指定这两个修饰符是错误的。DISTINCTROW是DISTINCT的同义词。DISTINCT可以与也使用WITH ROLLUP的查询一起使用。HIGH_PRIORITY使SELECT的优先级高于更新表的语句。这只应将其用于非常快且必须立即完成的查询。如果在表被锁定以进行读取时发出SELECT HIGH_PRIORITY查询,即使有更新语句在等待表释放,该查询也会运行。这仅影响仅使用表级锁定的存储引擎(例如MyISAM、MEMORY和MERGE)。STRAIGHT_JOIN强制优化器按照FROM子句中列出的顺序联接表。如果优化器以非最佳顺序联接表,可以使用此选项来加快查询速度。STRAIGHT_JOIN也可以在table_references列表中使用。请参阅 第 15.2.13.2 节,“JOIN 子句”。STRAIGHT_JOIN不适用于优化器将其视为const或system表的任何表。这样的表生成一行,在查询执行的优化阶段读取,并且在查询执行继续之前,对其列的引用将替换为相应的列值。这些表在EXPLAIN显示的查询计划中排在第一位。请参阅 第 10.8.1 节,“使用 EXPLAIN 优化查询”。此例外情况可能不适用于在外联接的 NULL 补充侧(即LEFT JOIN的右侧表或RIGHT JOIN的左侧表)上使用的const或system表。SQL_BIG_RESULT或SQL_SMALL_RESULT可以与GROUP BY或DISTINCT一起使用,以分别告诉优化器结果集有很多行或很小。对于SQL_BIG_RESULT,如果创建了基于磁盘的临时表,MySQL 会直接使用它们,并且更倾向于排序而不是使用带有GROUP BY元素键的临时表。对于SQL_SMALL_RESULT,MySQL 使用内存中的临时表来存储结果表,而不是使用排序。通常不需要这样做。SQL_BUFFER_RESULT强制将结果放入临时表中。这有助于 MySQL 尽早释放表锁,并在将结果集发送到客户端需要很长时间的情况下有所帮助。此修饰符只能用于顶级SELECT语句,不能用于子查询或UNION之后的语句。SQL_CALC_FOUND_ROWS告诉 MySQL 计算结果集中将有多少行,而忽略任何LIMIT子句。然后可以使用SELECT FOUND_ROWS()检索行数。请参阅 第 14.15 节,“信息函数”。注意SQL_CALC_FOUND_ROWS查询修饰符和随附的FOUND_ROWS()函数已弃用;预计在未来版本的 MySQL 中将删除它们。有关替代策略的信息,请参阅FOUND_ROWS()的说明。SQL_CACHE和SQL_NO_CACHE修饰符在 MySQL 9.0 之前与查询缓存一起使用。查询缓存已在 MySQL 9.0 中删除。SQL_CACHE修饰符也被删除。SQL_NO_CACHE已弃用,并且没有效果;预计在未来的 MySQL 版本中将删除它。