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
子句 explicit 分区选择,以在表名后面列出分区或子分区(或两者)列表(见 第 15.2.13.2 节,“JOIN 子句”)。在这种情况下,只从列出的分区中选择行,而忽略表的其他分区。有关更多信息和示例,见 第 26.5 节,“分区选择”。 -
如果给定,
WHERE
子句指示行必须满足的条件。where_condition
是一个对每行进行评估的表达式,以确定是否选择该行。如果没有WHERE
子句,则选择所有行。在
WHERE
表达式中,可以使用 MySQL 支持的任何函数和运算符,除了聚合(组)函数。见 第 11.5 节,“表达式” 和 第 14 章,《函数和运算符》。
SELECT
也可以用于检索不引用任何表的行。
例如:
mysql> SELECT 1 + 1;
-> 2
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
子句的更多信息:
-
一个
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
时使用标识符。前面的示例可以写成这样: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 节,“连接子句”。对于每个指定的表,您可以选择性地指定别名。table_references
tbl_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
前缀,除非引用可能会ambiguous。见 第 11.2.2 节,“标识符限定符”,以获取需要更明确的列引用形式的示例。 -
表引用可以使用
或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;
要按逆序排序,请在
ORDER BY
子句中添加DESC
(降序) 关键字到要排序的列名。默认是升序,可以使用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 在
ORDER BY
子句中解析未限定列或别名引用,方法是搜索select_expr
值,然后搜索FROM
子句中的表的列。对于GROUP BY
或HAVING
子句,它首先搜索FROM
子句,然后搜索select_expr
值。(对于GROUP BY
和HAVING
,这与 MySQL 5.0 之前的行为不同,该行为使用与ORDER BY
相同的规则。) -
LIMIT
子句可以用来约束SELECT
语句返回的行数。LIMIT
需要一个或两个数字参数,这两个参数必须都是非负整数常量,以下是例外情况:-
在预备语句中,可以使用
?
占位符标记指定LIMIT
参数。 -
在存储程序中,可以使用整数值的routine参数或局部变量指定
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
表中检索一行: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 语句”。 -
如果您使用
FOR UPDATE
与使用页锁或行锁的存储引擎,查询检查的行将被写锁定,直到当前事务结束。您不能在
SELECT
语句中使用FOR UPDATE
,例如CREATE TABLE
。(如果您尝试这样做,语句将被拒绝,错误信息为 无法更新表 'new_table
SELECT ... FROMold_table
...old_table
',因为 'new_table
' 正在被创建。)FOR SHARE
和LOCK IN SHARE MODE
设置共享锁,允许其他事务读取检查的行,但不允许更新或删除它们。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
的情况下,使用锁定子句与其他锁定子句组合将返回错误。指定同一个表在多个锁定子句中将返回错误。如果在tbl_name
SELECT
语句中指定了别名作为表名,那么锁定子句只能使用别名。如果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
语句的优先级高于更新表的语句。您应该仅将其用于非常快速的查询,必须立即执行。使用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 直接使用基于磁盘的临时表,如果它们被创建,并且优先使用排序而不是使用带有 GROUP BY 元素的临时表的键。对于SQL_SMALL_RESULT
,MySQL 使用内存中的临时表来存储结果表,而不是使用排序。这通常不需要。 -
SQL_BUFFER_RESULT
强制结果被放入临时表中。这有助于 MySQL 早期释放表锁,并且在将结果集发送到客户端时需要很长时间的情况下有所帮助。该修饰符只能用于顶级SELECT
语句,而不是子查询或以下UNION
。 -
SQL_CALC_FOUND_ROWS
告诉 MySQL 计算结果集中的行数,忽略任何LIMIT
子句。然后可以使用SELECT FOUND_ROWS()
检索行数。见 第 14.15 节,“信息函数”。NoteSQL_CALC_FOUND_ROWS
查询修饰符和伴随的FOUND_ROWS()
函数已弃用;预计它们将在未来版本的 MySQL 中被删除。见FOUND_ROWS()
的描述,以获取替代策略的信息。 -
在 MySQL 8.3 之前,
SQL_CACHE
和SQL_NO_CACHE
修饰符用于查询缓存。查询缓存在 MySQL 8.3 中被删除。SQL_CACHE
修饰符也被删除。SQL_NO_CACHE
已弃用,且没有效果;预计它将在未来 MySQL 版本中被删除。