15.2.13 选择语句
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节,“连接子句”中描述。 -
SELECT
支持明确的分区选择,使用分区选择,在连接子句中指定分区列表或子分区(或两者)。在这种情况下,只从指定的分区中选择行,其他分区将被忽略。更多信息和示例,请见第26.5节,“分区选择”。 -
如果给定WHERE子句,表示要选择的行必须满足的条件。
where_condition
是一个表达式,用于评估每个要选择的行。语句选择所有行,如果没有WHERE子句。在
WHERE
表达式中,您可以使用 MySQL 支持的任何函数和操作符,除了聚合(组)函数。请参阅第11.5节,“表达式”,和第14章,《函数和操作符》。
SELECT
也可以用来检索计算结果不依赖于任何表的行。
例如:
mysql> SELECT 1 + 1;
-> 2
您允许指定 DUAL
作为 dummy 表名,在没有引用任何表的情况下:
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 列表组成的选择列表,指示要检索的列。项指定一个列或表达式,可以使用 *
-shorthand:
-
一个只包含一个未qualified
*
的选择列表可以用作简写,来选择所有列来自所有表:SELECT * FROM t1 INNER JOIN t2 ...
-
可以用作qualified简写,来选择来自指定表的所有列:tbl_name
.*SELECT t1.*, t2.* FROM t1 INNER JOIN t2 ...
-
如果一个表有不可见列,
*
和
不包括它们。要包括不可见列,必须明确地引用它们。tbl_name
.* -
使用未qualified
*
和其他项在选择列表中可能会产生解析错误。例如:SELECT id, * FROM t1
为了避免这个问题,使用qualified
参考:tbl_name
.*SELECT id, t1.* FROM t1
使用qualified
参考对于每个表在选择列表中:tbl_name
.*SELECT AVG(score), t1.* FROM t1 ...
以下列表提供了其他 SELECT
子句的信息:
-
一个
select_expr
可以使用AS
给定别名。别名用于表达式的列名,可以在alias_name
GROUP BY
、ORDER BY
或HAVING
子句中使用。例如:SELECT CONCAT(last_name,', ',first_name) AS full_name FROM mytable ORDER BY full_name;
关键字
AS
在将一个select_expr
与标识符alias时是可选的。前面的示例可以写成以下形式: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 Clause”。对于每个指定的表,您可以选择指定别名。table_references
tbl_name [[AS] alias] [index_hint]
使用索引提示可以让优化器在查询处理时了解索引选择的信息。关于指定这些提示的语法,请见第10.9.4节,“Index Hints”。
您可以使用
SET max_seeks_for_key=
作为强制MySQL优先选择键扫描而不是表扫描的alternative方法。见第7.1.8节,“Server System Variables”。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节,“Identifier Qualifiers”,了解歧义的示例,该歧义需要更明确的列引用形式。 -
表引用可以使用
或tbl_name
ASalias_name
tbl_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节,“聚合函数”的描述。 -
HAVING
子句,像WHERE
子句一样,指定选择条件。WHERE
子句指定列在选择列表中的条件,但不能引用聚合函数。HAVING
子句指定组的条件,通常由GROUP BY
子句形成的组。查询结果只包括满足HAVING
条件的组。如果没有GROUP BY
,所有行隐式形成一个聚合组。HAVING
子句在 nearly最后应用于客户端,且没有优化。(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 在
ORDER BY
子句中解析未qualified 的列或别名引用,通过在select_expr
值中搜索,然后在FROM
子句中的表列中搜索。在GROUP BY
或HAVING
子句中,它首先搜索FROM
子句,然后搜索select_expr
值。 (对于GROUP BY
和HAVING
,这与 MySQL 5.0 之前的行为不同,该行为与ORDER BY
的规则相同。) -
LIMIT
子句可以用来限制SELECT
语句返回的行数。LIMIT
接受一个或两个非负整数常量,以下情况除外:-
在预备语句中,
LIMIT
参数可以使用?
占位符来指定。 -
在存储程序中,
LIMIT
参数可以使用整数值的 routine 参数或本地变量来指定。
使用两个参数时,第一个参数指定从结果集中返回的第一个行的偏移量,第二个参数指定返回的最大行数。结果集的初始行的偏移量为 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
表中返回一行: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_count
OFFSEToffset
如果
LIMIT
在括号内的查询表达式中出现,并且在外部查询中也应用于该语句,结果将是未定义的,并且可能在MySQL的未来版本中发生变化。 -
-
SELECT ... INTO
形式的SELECT
允许将查询结果写入文件或存储在变量中。更多信息,请参见第15.2.13.1节,“SELECT ... INTO Statement”。 -
如果您使用
FOR UPDATE
与存储引擎使用页或行锁定的存储引擎,查询中examined的行将在当前事务结束前保持写锁定状态。您不能将
FOR UPDATE
作为SELECT
的一部分使用在语句中,如CREATE TABLE
。 (如果您尝试这样做,语句将被拒绝,并显示错误Can't update table 'new_table
SELECT ... FROMold_table
...old_table
' while 'new_table
' is being created。)FOR SHARE
和LOCK IN SHARE MODE
设置共享锁,使其他事务可以读取examined的行,但不能更新或删除它们。FOR SHARE
和LOCK IN SHARE MODE
是等效的。然而,FOR SHARE
,像FOR UPDATE
一样,支持NOWAIT
、SKIP LOCKED
和OF
选项。tbl_name
FOR SHARE
是LOCK IN SHARE MODE
的替代品,但LOCK IN SHARE MODE
仍然可用于向后兼容性。NOWAIT
使FOR UPDATE
或FOR SHARE
查询立即执行,如果无法获取行锁,因为另一个事务持有锁定。SKIP LOCKED
使FOR UPDATE
或FOR SHARE
查询立即执行,排除由另一个事务锁定的行从结果集中。NOWAIT
和SKIP LOCKED
选项在语句级别的复制中是安全的。Note跳过锁定的行的查询返回不一致的数据视图。
SKIP LOCKED
因此不适用于一般事务工作。但是,它可能用于避免锁定竞争,当多个会话访问同一个队列表。OF
将对指定的表应用tbl_name
FOR UPDATE
和FOR SHARE
查询。例如:SELECT * FROM t1, t2 FOR SHARE OF t1 FOR UPDATE OF t2;
当
OF
省略时,所有查询块引用的表都将被锁定。因此,在不使用tbl_name
OF
与其他锁定子句时,返回错误。指定多个锁定子句中的同一表名返回错误。如果在SELECT语句中指定了别名,锁定子句只能使用别名。如果SELECT语句没有显式指定别名,锁定子句只能指定实际表名。tbl_name
有关
FOR UPDATE
和FOR SHARE
的更多信息,请见第17.7.2.4节,“Locking Reads”。有关NOWAIT
和SKIP LOCKED
选项的更多信息,请见Locking Read Concurrency with NOWAIT and 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 优化查询”。这项例外可能不适用于const
或system
表,如果这些表用于NULL
-补充的外连接的右侧(即LEFT JOIN
的右侧或RIGHT JOIN
的左侧。 -
SQL_BIG_RESULT
或SQL_SMALL_RESULT
可以与GROUP BY
或DISTINCT
一起使用,以告诉优化器结果集有很多行或是小的结果。对于SQL_BIG_RESULT
,MySQL 直接使用磁盘临时表,如果创建了临时表,并且优先使用排序而不是使用临时表。对于SQL_SMALL_RESULT
,MySQL 使用内存临时表来存储结果表,而不是使用排序。这通常不需要。 -
SQL_BUFFER_RESULT
强制结果被放入临时表。这有助于 MySQL 早释放表锁,并在将结果集发送到客户端时帮助。在使用SQL_BUFFER_RESULT
时,需要在顶级SELECT
语句中使用该语句,不可以在子查询或UNION
中使用。 -
SQL_CALC_FOUND_ROWS
告诉 MySQL 计算结果集的行数,忽略任何LIMIT
子句。然后,可以使用SELECT FOUND_ROWS()
获取行数。见第14.15节,“信息函数”。NoteSQL_CALC_FOUND_ROWS
-
SQL_CACHE和SQL_NO_CACHE修饰符在MySQL 8.4之前与查询缓存一起使用。MySQL 8.4中删除了查询缓存。SQL_CACHE修饰符也被删除。SQL_NO_CACHE已经弃用,没有效果,预计将在未来的MySQL版本中删除。