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_nameGROUP 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_referencestbl_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_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节,“聚合函数”的描述。 -
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_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 Statement”。 -
如果您使用
FOR UPDATE与存储引擎使用页或行锁定的存储引擎,查询中examined的行将在当前事务结束前保持写锁定状态。您不能将
FOR UPDATE作为SELECT的一部分使用在语句中,如CREATE TABLE。 (如果您尝试这样做,语句将被拒绝,并显示错误Can't update table 'new_tableSELECT ... 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_nameFOR 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_nameFOR UPDATE和FOR SHARE查询。例如:SELECT * FROM t1, t2 FOR SHARE OF t1 FOR UPDATE OF t2;当
OF省略时,所有查询块引用的表都将被锁定。因此,在不使用tbl_nameOF与其他锁定子句时,返回错误。指定多个锁定子句中的同一表名返回错误。如果在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版本中删除。