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语句最常用的子句如下:

使用诸如 tableMyISAM之类的存储引擎执行 table 级锁定(并因此执行分区锁定)的 table 中的SELECT ... PARTITION仅锁定PARTITION选项命名的分区或子分区。

有关更多信息,请参见第 22.6.4 节“分区和锁定”

WHEREtable 达式中,可以使用 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 * FROM t1 INNER JOIN t2 ...
SELECT t1.*, t2.* FROM t1 INNER JOIN t2 ...
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 节,“列别名问题”

tbl_name [[AS] alias] [index_hint]

索引提示的使用为优化器提供了有关在查询处理期间如何选择索引的信息。有关指定这些提示的语法的说明,请参见第 8.9.4 节“索引提示”

您可以使用SET max_seeks_for_key=value作为强制 MySQL 首选键扫描而不是 table 扫描的替代方法。参见第 5.1.7 节“服务器系统变量”

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 标准中删除。

SELECT a, COUNT(b) FROM test_table GROUP BY a ORDER BY NULL;

不建议使用隐式GROUP BY排序(即在没有ASCDESC指示符的情况下进行排序)或GROUP BY的显式排序(即对GROUP BY列使用显式ASCDESC指示符)。要产生给定的排序 Sequences,请提供ORDER BY子句。

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列中的列优先。

SELECT col_name FROM tbl_name HAVING col_name > 0;

Rewrite 这个:

SELECT col_name FROM tbl_name WHERE col_name > 0;
SELECT user, MAX(salary) FROM users
  GROUP BY user HAVING MAX(salary) > 10;

(这在某些旧版本的 MySQL 中不起作用.)

SELECT 12 AS a, a FROM t GROUP BY a;

在该语句中,两列的名称均为a。为确保将正确的列用于分组,请对每个* select_expr *使用不同的名称。

有两个参数,第一个参数指定要返回的第一行的偏移量,第二个参数指定要返回的最大行数。初始行的偏移量是 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

对于准备好的语句,可以使用占位符。以下语句将从tbltable 返回一行:

SET @a=1;
PREPARE STMT FROM 'SELECT * FROM tbl LIMIT ?';
EXECUTE STMT USING @a;

以下语句将返回tbltable 的第二到第六行:

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 版本中可能会更改。

UNION语句中不允许使用PROCEDURE子句。

Note

自 MySQL 5.7.18 起不赞成使用PROCEDURE语法,并且在 MySQL 8.0 中已将其删除。

此外,您不能在创建 tablenew_table SELECT ... FROM old_table ...之类的语句中将FOR UPDATE用作SELECT的一部分。 (如果尝试这样做,则会在创建'* new_table '的同时,以错误无法更新 table' old_table *'拒绝该语句.)这是 MySQL 5.5 及更早版本的行为更改,允许创建 table...选择语句可对正在创建的 table 以外的 table 进行更改。

SELECT关键字之后,可以使用许多修饰符来影响语句的操作。 HIGH_PRIORITYSTRAIGHT_JOIN和以SQL_开头的修饰符是标准 SQL 的 MySQL 扩展。

HIGH_PRIORITY不能与UNIONSELECT语句一起使用。

STRAIGHT_JOIN不适用于优化器视为constsystemtable 的任何 table。这样的 table 产生一行,在查询执行的优化阶段读取该 table,并在执行查询之前将其列的引用替换为适当的列值。这些 table 将首先出现在EXPLAIN显示的查询计划中。参见第 8.8.1 节“使用 EXPLAIN 优化查询”。此异常可能不适用于在外部联接的NULL补码侧使用的constsystemtable(即LEFT JOIN的右侧 table 或RIGHT JOIN的左侧 table)。

这两个修饰符是互斥的,如果同时指定了它们,则会发生错误。此外,在子查询(包括FROM子句中的子查询)和除第一个SELECT之外的并集中的SELECT语句中,不允许使用这些修饰符。

对于视图,如果SQL_NO_CACHE出现在查询的任何SELECT中,则适用。对于可缓存的查询,如果SQL_CACHE出现在查询所引用的视图的前SELECT中,则应用SQL_CACHE

Note

从 MySQL 5.7.20 开始,查询缓存已弃用,并在 MySQL 8.0 中删除。弃用包括SQL_CACHESQL_NO_CACHE

使用诸如 tableMyISAM之类的存储引擎的分区 table 中的SELECT使用 table 级锁仅锁定那些包含与SELECT语句WHERE子句匹配的行的分区。 (对于采用行级锁定的InnoDB之类的存储引擎,不会发生这种情况。)有关更多信息,请参见第 22.6.4 节“分区和锁定”

首页