文档首页
MySQL 8.4 参考手册
相关文档 下载本手册
PDF (US Ltr) - 39.9Mb
PDF (A4) - 40.0Mb
手册页 (TGZ) - 258.5Kb
手册页 (Zip) - 365.5Kb
信息 (Gzip) - 4.0Mb
信息 (Zip) - 4.0Mb


MySQL 8.4 参考手册  /  ...  /  SELECT 语句

15.2.13 SELECT 语句

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 子句进行显式分区选择,该子句在 table_reference 中的表名后面跟有一个分区或子分区(或两者)的列表(参见 第 15.2.13.2 节,“JOIN 子句”)。在这种情况下,仅从列出的分区中选择行,而忽略表的任何其他分区。有关更多信息和示例,请参见 第 26.5 节,“分区选择”。

  • WHERE 子句(如果给出)指示行必须满足才能被选中的条件。 where_condition 是一个表达式,对于要选择的每一行,该表达式的计算结果为真。如果没有 WHERE 子句,则该语句将选择所有行。

    在 WHERE 表达式中,您可以使用 MySQL 支持的任何函数和运算符,但聚合(分组)函数除外。请参见 第 11.5 节,“表达式” 和 第 14 章, 函数和运算符。

SELECT 也可以用于检索不参考任何表计算的行。

例如

mysql> SELECT 1 + 1;
        -> 2

在没有引用任何表的情况下,允许您在需要所有 SELECT 语句都应具有 FROM 子句和其他子句的情况下,将 DUAL 指定为虚拟表名。

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

  • 仅包含单个非限定 * 的选择列表可以用作速记,以选择所有表中的所有列

    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 子句的更多信息

  • 可以使用 AS alias_name 为 select_expr 指定别名。别名用作表达式的列名,并且可以在 GROUP BY、ORDER BY 或 HAVING 子句中使用。例如

    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 表达式之间的逗号,则可能会出现一个微妙的问题:MySQL 将第二个表达式解释为别名。例如,在以下语句中,columnb 被视为别名

    SELECT columna columnb FROM mytable;

    因此,在指定列别名时,最好养成显式使用 AS 的习惯。

    不允许在 WHERE 子句中引用列别名,因为在执行 WHERE 子句时,列值可能尚未确定。请参见 第 B.3.4.4 节,“列别名的问题”。

  • FROM table_references 子句指示从中检索行的表。如果命名多个表,则表示您正在执行联接。有关联接语法的更多信息,请参见 第 15.2.13.2 节,“JOIN 子句”。对于指定的每个表,您可以选择指定一个别名。

    tbl_name [[AS] alias] [index_hint]

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

    您可以使用 SET max_seeks_for_key=value 作为强制 MySQL 首选键扫描而不是表扫描的另一种方法。请参见 第 7.1.8 节,“服务器系统变量”。

  • 您可以将默认数据库中的表称为 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 节,“标识符限定符”,以获取需要更明确的列引用形式的歧义示例。

  • 可以使用 tbl_name AS alias_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 节,“聚合函数” 中对 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 列中的列。

  • 不要对应该出现在 WHERE 子句中的项目使用 HAVING。例如,不要写以下内容

    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 通过在 select_expr 值中搜索,然后在 FROM 子句中的表的列中搜索,来解析 ORDER BY 子句中的非限定列或别名引用。对于 GROUP BY 或 HAVING 子句,它会在搜索 select_expr 值之前先搜索 FROM 子句。(对于 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 表返回一行

    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 OFFSET offset 语法。

    如果 LIMIT 出现在带括号的查询表达式中,并且也应用于外部查询,则结果未定义,并且在未来版本的 MySQL 中可能会发生变化。

  • SELECT ... INTO 形式的 SELECT 语句允许将查询结果写入文件或存储在变量中。有关更多信息,请参阅第 15.2.13.1 节“SELECT ... INTO 语句”。

  • 如果将 FOR UPDATE 与使用页面锁或行锁的存储引擎一起使用,则查询检查的行将被写锁定,直到当前事务结束。

    不能在诸如 CREATE TABLE new_table SELECT ... FROM old_table ... 之类的语句中使用 FOR UPDATE 作为 SELECT 的一部分。(如果尝试这样做,则该语句将被拒绝,并显示错误 在创建“new_table”时无法更新表“old_table”。)

    FOR SHARE 和 LOCK IN SHARE MODE 设置共享锁,允许其他事务读取已检查的行,但不能更新或删除它们。FOR SHARE 和 LOCK IN SHARE MODE 是等效的。但是,与 FOR UPDATE 一样,FOR SHARE 也支持 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 选项对于基于语句的复制来说是不安全的。

    注意

    跳过已锁定行的查询返回的数据视图不一致。因此,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 的优先级高于更新表的语句。这应该仅用于非常快且必须立即完成的查询。如果在表被锁定以供读取时发出 SELECT HIGH_PRIORITY 查询,则即使有更新语句正在等待表释放,该查询也会运行。这只影响仅使用表级锁定的存储引擎(例如 MyISAM、MEMORY 和 MERGE)。

    HIGH_PRIORITY 不能与作为 UNION 的一部分的 SELECT 语句一起使用。

  • STRAIGHT_JOIN 强制优化器按照 FROM 子句中列出的顺序连接表。如果优化器以非最佳顺序连接表,则可以使用此选项来加速查询。STRAIGHT_JOIN 也可以在 table_references 列表中使用。请参阅第 15.2.13.2 节“JOIN 子句”。

    STRAIGHT_JOIN 不适用于优化器将其视为 const 或 system 表的任何表。这样的表只生成一行,在查询执行的优化阶段读取,并且在查询执行继续之前,对其列的引用将被替换为相应的列值。这些表在 EXPLAIN 显示的查询计划中排在最前面。请参阅第 10.8.1 节“使用 EXPLAIN 优化查询”。此例外情况可能不适用于在外部连接的 NULL 补充侧(即 LEFT JOIN 的右侧表或 RIGHT JOIN 的左侧表)使用的 const 或 system 表。

  • 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 节“信息函数”。

    注意

    SQL_CALC_FOUND_ROWS 查询修饰符和随附的 FOUND_ROWS() 函数已被弃用;预计它们将在未来版本的 MySQL 中被删除。有关替代策略的信息,请参阅 FOUND_ROWS() 的描述。

  • SQL_CACHE 和 SQL_NO_CACHE 修饰符在 MySQL 8.4 之前与查询缓存一起使用。查询缓存已在 MySQL 8.4 中删除。SQL_CACHE 修饰符也被删除。SQL_NO_CACHE 已被弃用,并且不起作用;预计它将在未来的 MySQL 版本中被删除。