13.2.9 SELECT 语句
SELECT
[ALL | DISTINCT | DISTINCTROW ]
[HIGH_PRIORITY]
[STRAIGHT_JOIN]
[SQL_SMALL_RESULT] [SQL_BIG_RESULT] [SQL_BUFFER_RESULT]
[SQL_CACHE | 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}
[ASC | DESC], ... [WITH ROLLUP]]
[HAVING where_condition]
[ORDER BY {col_name | expr | position}
[ASC | DESC], ...]
[LIMIT {[offset,] row_count | row_count OFFSET offset}]
[PROCEDURE procedure_name(argument_list)]
[into_option]
[FOR UPDATE | LOCK IN SHARE MODE]
into_option: {
INTO OUTFILE 'file_name'
[CHARACTER SET charset_name]
export_options
| INTO DUMPFILE 'file_name'
| INTO var_name [, var_name] ...
}
SELECT用于检索从一个或多个 table 中选择的行,并且可以包含UNION语句和子查询。参见第 13.2.9.3 节“ UNION 子句”和第 13.2.10 节,“子查询”。
SELECT语句最常用的子句如下:
-
每个*
select_expr
table 示要检索的列。必须至少有一个select_expr
*。 -
table_references
*table 示要从中检索行的 table。其语法在第 13.2.9.2 节“ JOIN 子句”中描述。
-
SELECT
支持使用PARTITION
进行显式分区选择,其中table_reference
*中的 table 名后面有分区或子分区(或两者)的列 table(请参见第 13.2.9.2 节“ JOIN 子句”)。在这种情况下,仅从列出的分区中选择行,并且忽略 table 的任何其他分区。有关更多信息和示例,请参见第 22.5 节“分区选择”。
使用诸如 tableMyISAM之类的存储引擎执行 table 级锁定(并因此执行分区锁定)的 table 中的SELECT ... PARTITION
仅锁定PARTITION
选项命名的分区或子分区。
有关更多信息,请参见第 22.6.4 节“分区和锁定”。
WHERE
子句(如果提供)指示必须满足的条件才能选择行。 *where_condition
*是对要选择的每一行求值为 true 的 table 达式。如果没有WHERE
子句,该语句将选择所有行。
在WHERE
table 达式中,可以使用 MySQL 支持的任何函数和运算符,但聚合(摘要)函数除外。参见第 9.5 节“table 达式”和第 12 章,函数和运算符。
SELECT还可以用于检索不参考任何 table 而计算的行。
For example:
mysql> SELECT 1 + 1;
-> 2
在未引用任何 table 的情况下,您可以指定DUAL
作为虚拟 table 名称:
mysql> SELECT 1 + 1 FROM DUAL;
-> 2
DUAL
纯粹是为了方便那些要求所有SELECT语句应包含FROM
以及可能包含其他子句的人。 MySQL 可能会忽略这些子句。如果没有引用 table,MySQL 不需要FROM DUAL
。
通常,必须严格按照语法说明中显示的 Sequences 给出所使用的子句。例如,一个HAVING
子句必须在任何GROUP BY
子句之后和任何ORDER BY
子句之前。 INTO
子句(如果存在)可以出现在语法描述指示的任何位置,但是在给定语句内只能出现一次,而不可以出现在多个位置。有关INTO
的更多信息,请参见第 13.2.9.1 节“ SELECT ... INTO 语句”。
select_expr
*术语列 table 包括选择列 table,该列 table 指示要检索的列。术语指定列或 table 达式,或者可以使用*
-简写:
- 仅包含一个不合格的
*
的选择列 table 可以用作从所有 table 中选择所有列的速记:
SELECT * FROM t1 INNER JOIN t2 ...
tbl_name.*
可以用作限定快捷方式来从命名 table 中选择所有列:
SELECT t1.*, t2.* FROM t1 INNER JOIN t2 ...
- 将不合格的
*
与选择列 table 中的其他项目一起使用可能会产生解析错误。为避免此问题,请使用合格的tbl_name.*
参考
SELECT AVG(score), t1.* FROM t1 ...
以下列 table 提供了有关其他SELECT
子句的其他信息:
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
*table 达式之间的逗号,则会出现细微问题:MySQL 将第二个 table 达式解释为别名。例如,在下面的语句中,columnb
被视为别名:
SELECT columna columnb FROM mytable;
因此,在指定列别名时,最好养成显式使用AS
的习惯。
不允许在WHERE
子句中引用列别名,因为在执行WHERE
子句时可能尚未确定列值。参见B.4.4.4 节,“列别名问题”。
-
FROM table_references
子句指示要从中检索行的 table。如果您命名多个 table,则说明您正在执行联接。有关连接语法的信息,请参见第 13.2.9.2 节“ JOIN 子句”。对于指定的每个 table,您可以选择指定别名。
tbl_name [[AS] alias] [index_hint]
索引提示的使用为优化器提供了有关在查询处理期间如何选择索引的信息。有关指定这些提示的语法的说明,请参见第 8.9.4 节“索引提示”。
您可以使用SET max_seeks_for_key=value
作为强制 MySQL 首选键扫描而不是 table 扫描的替代方法。参见第 5.1.7 节“服务器系统变量”。
-
您可以在默认数据库中将 table 称为*
tbl_name
或db_name
*。 *tbl_name
明确指定数据库。您可以将列称为col_name
,tbl_name
*。 *col_name
或db_name
*。 *tbl_name
*。 *col_name
。您无需指定tbl_name
或db_name
*。 *tbl_name
*列引用的前缀,除非引用不明确。有关需要更明确的列引用形式的歧义示例,请参见第 9.2.2 节“标识符限定符”。 -
可以使用
tbl_name AS alias_name
或*tbl_name alias_name
*为 table 引用添加别名。这些语句是等效的:
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;
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;
要以相反的 Sequences 进行排序,请将DESC
(降序)关键字添加到排序依据的ORDER BY
子句中的列名称中。默认为升序;可以使用ASC
关键字明确指定。
如果ORDER BY
出现在带括号的查询 table 达式中,并且也应用在外部查询中,则结果是不确定的,并且在将来的 MySQL 版本中可能会更改。
不建议使用列位置,因为该语法已从 SQL 标准中删除。
-
MySQL 扩展了
GROUP BY
子句,因此您也可以在该子句中命名的列之后指定ASC
和DESC
。但是,不赞成使用此语法。要产生给定的排序 Sequences,请提供ORDER BY
子句。 -
如果使用
GROUP BY
,则根据GROUP BY
列对输出行进行排序,就好像您在同一列中使用ORDER BY
一样。为了避免GROUP BY
产生的排序开销,请添加ORDER BY NULL
:
SELECT a, COUNT(b) FROM test_table GROUP BY a ORDER BY NULL;
不建议使用隐式GROUP BY
排序(即在没有ASC
或DESC
指示符的情况下进行排序)或GROUP BY
的显式排序(即对GROUP BY
列使用显式ASC
或DESC
指示符)。要产生给定的排序 Sequences,请提供ORDER BY
子句。
-
当您使用
ORDER BY
或GROUP BY
对SELECT中的列进行排序时,服务器仅使用max_sort_length系统变量指示的初始字节数对值进行排序。 -
MySQL 扩展了
GROUP BY
的使用,以允许选择GROUP BY
子句中未提及的字段。如果您没有从查询中获得预期的结果,请阅读第 12.20 节“聚合函数”中对GROUP BY
的描述。 -
GROUP BY
允许使用WITH ROLLUP
修饰符。参见第 12.20.2 节“按修饰符分组”。 -
几乎是最后一次应用
HAVING
子句,即将项目发送到 Client 端之前,没有进行优化。 (在HAVING
之后应用LIMIT
.)
SQL 标准要求HAVING
必须仅引用GROUP BY
子句中的列或聚合函数中使用的列。但是,MySQL 支持对此行为的扩展,并允许HAVING
引用SELECT列 table 中的列以及外部子查询中的列。
如果HAVING
子句引用的列不明确,则会出现警告。在以下语句中,col2
是不明确的,因为它既用作别名又用作列名:
SELECT COUNT(col1) AS col2 FROM t GROUP BY col2 HAVING col2 = 2;
优先考虑标准 SQL 行为,因此,如果在GROUP BY
中同时使用HAVING
列名,并且在输出列列 table 中将其用作别名列,则对GROUP BY
列中的列优先。
- 请勿将
HAVING
用于应包含在WHERE
子句中的项目。例如,不要写以下内容:
SELECT col_name FROM tbl_name HAVING col_name > 0;
Rewrite 这个:
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
*使用不同的名称。
-
MySQL 通过搜索*
select_expr
值,然后在FROM
子句中的 table 的列中,来解析ORDER BY
子句中的不合格列或别名引用。对于GROUP BY
或HAVING
子句,它先搜索FROM
子句,然后再搜索select_expr
*值。 (对于GROUP BY
和HAVING
,这与使用与ORDER BY
相同的规则的 MySQL 5.0 之前的行为不同.) -
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_count
等效于LIMIT 0, row_count
。
对于准备好的语句,可以使用占位符。以下语句将从tbl
table 返回一行:
SET @a=1;
PREPARE STMT FROM 'SELECT * FROM tbl LIMIT ?';
EXECUTE STMT USING @a;
以下语句将返回tbl
table 的第二到第六行:
SET @skip=1; SET @numrows=5;
PREPARE STMT FROM 'SELECT * FROM tbl LIMIT ?, ?';
EXECUTE STMT USING @skip, @numrows;
为了与 PostgreSQL 兼容,MySQL 还支持LIMIT row_count OFFSET offset
语法。
如果LIMIT
出现在带括号的查询 table 达式中,并且也应用在外部查询中,则结果是不确定的,并且在将来的 MySQL 版本中可能会更改。
-
PROCEDURE
子句命名一个过程,该过程应处理结果集中的数据。有关示例,请参见第 8.4.2.4 节“使用过程分析”,它描述了ANALYSE
,该过程可用于获取有关最佳列数据类型的建议,这可能有助于减小 table 的大小。
UNION语句中不允许使用PROCEDURE
子句。
Note
自 MySQL 5.7.18 起不赞成使用PROCEDURE
语法,并且在 MySQL 8.0 中已将其删除。
-
选择...进入形式的SELECT使查询结果可以写入文件或存储在变量中。有关更多信息,请参见第 13.2.9.1 节“ SELECT ... INTO 语句”。
-
如果将
FOR UPDATE
与使用页面锁定或行锁定的存储引擎一起使用,则查询检查的行将被写锁定,直到当前事务结束为止。使用LOCK IN SHARE MODE
设置共享锁,该共享锁允许其他事务读取已检查的行,但不能更新或删除它们。参见第 14.7.2.4 节“锁定读取”。
此外,您不能在创建 tablenew_table SELECT ... FROM old_table ...之类的语句中将FOR UPDATE
用作SELECT的一部分。 (如果尝试这样做,则会在创建'* new_table
'的同时,以错误无法更新 table' old_table
*'拒绝该语句.)这是 MySQL 5.5 及更早版本的行为更改,允许创建 table...选择语句可对正在创建的 table 以外的 table 进行更改。
在SELECT关键字之后,可以使用许多修饰符来影响语句的操作。 HIGH_PRIORITY
,STRAIGHT_JOIN
和以SQL_
开头的修饰符是标准 SQL 的 MySQL 扩展。
ALL
和DISTINCT
修饰符指定是否应返回重复的行。ALL
(默认值)指定应返回所有匹配的行,包括重复行。DISTINCT
指定从结果集中删除重复的行。同时指定两个修饰符是错误的。DISTINCTROW
是DISTINCT
的同义词。
HIGH_PRIORITY
的优先级比更新 table 的语句的SELECT高。您只应将此用于非常快速且必须立即执行的查询。即使有一条更新语句 awaittable 空闲,在锁定 table 以进行读取时发出的SELECT HIGH_PRIORITY
查询也会运行。这仅影响仅使用 table 级锁定(例如MyISAM
,MEMORY
和MERGE
)的存储引擎。
HIGH_PRIORITY
不能与UNION的SELECT语句一起使用。
STRAIGHT_JOIN
强制优化器按照FROM
子句中列出的 Sequences 连接 table。如果优化器以非最佳 Sequences 连接 table,则可以使用它来加快查询速度。STRAIGHT_JOIN
也可以在*table_references
*列 table 中使用。参见第 13.2.9.2 节“ JOIN 子句”。
STRAIGHT_JOIN
不适用于优化器视为const或systemtable 的任何 table。这样的 table 产生一行,在查询执行的优化阶段读取该 table,并在执行查询之前将其列的引用替换为适当的列值。这些 table 将首先出现在EXPLAIN显示的查询计划中。参见第 8.8.1 节“使用 EXPLAIN 优化查询”。此异常可能不适用于在外部联接的NULL
补码侧使用的const或systemtable(即LEFT JOIN
的右侧 table 或RIGHT JOIN
的左侧 table)。
SQL_BIG_RESULT
或SQL_SMALL_RESULT
可以与GROUP BY
或DISTINCT
一起使用,以告诉优化器结果集分别具有很多行或很小。对于SQL_BIG_RESULT
,如果创建了基于磁盘的临时 table,则 MySQL 直接使用基于磁盘的临时 table,并且比使用在GROUP BY
元素上带有键的临时 table 更喜欢排序。对于SQL_SMALL_RESULT
,MySQL 使用内存中临时 table 存储结果 table,而不是使用排序。通常不需要。
SQL_BUFFER_RESULT
强制将结果放入临时 table 中。这有助于 MySQL 及早释放 table 锁定,并在将结果集发送到 Client 端花费很长时间的情况下提供帮助。此修饰符只能用于顶级SELECT语句,而不能用于子查询或UNION之后的语句。
SQL_CALC_FOUND_ROWS
告诉 MySQL 忽略任何LIMIT
子句,计算结果集中将有多少行。然后可以使用SELECT FOUND_ROWS()
检索行数。参见第 12.15 节“信息功能”。
SQL_CACHE
和SQL_NO_CACHE
修饰符影响查询结果在查询缓存中的缓存(请参阅第 8.10.3 节“ MySQL 查询缓存”)。SQL_CACHE
告诉 MySQL 将结果存储在查询缓存中,如果它是可缓存的并且query_cache_type系统变量的值为2
或DEMAND
。使用SQL_NO_CACHE
,服务器不使用查询缓存。它既不检查查询缓存以查看结果是否已经缓存,也不缓存查询结果。
这两个修饰符是互斥的,如果同时指定了它们,则会发生错误。此外,在子查询(包括FROM
子句中的子查询)和除第一个SELECT之外的并集中的SELECT语句中,不允许使用这些修饰符。
对于视图,如果SQL_NO_CACHE
出现在查询的任何SELECT中,则适用。对于可缓存的查询,如果SQL_CACHE
出现在查询所引用的视图的前SELECT中,则应用SQL_CACHE
。
Note
从 MySQL 5.7.20 开始,查询缓存已弃用,并在 MySQL 8.0 中删除。弃用包括SQL_CACHE
和SQL_NO_CACHE
。
使用诸如 tableMyISAM之类的存储引擎的分区 table 中的SELECT
使用 table 级锁仅锁定那些包含与SELECT
语句WHERE
子句匹配的行的分区。 (对于采用行级锁定的InnoDB之类的存储引擎,不会发生这种情况。)有关更多信息,请参见第 22.6.4 节“分区和锁定”。