Documentation Home
MySQL 8.3 Reference Manual
Related Documentation Download this Manual
PDF (US Ltr) - 40.8Mb
PDF (A4) - 40.9Mb
Man Pages (TGZ) - 294.0Kb
Man Pages (Zip) - 409.0Kb
Info (Gzip) - 4.0Mb
Info (Zip) - 4.0Mb
Excerpts from this Manual

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 操作和子查询。INTERSECTEXCEPT 操作也受支持。UNIONINTERSECTEXCEPT 运算符在本节后面将详细描述。见 第 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

您可以在不引用任何表的情况下指定 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 项组成选择列表,指示要检索的列。项可以指定列或表达式,也可以使用 *-快捷方式:

  • 仅包含单个未限定 * 的选择列表可以用作快捷方式来选择所有表的所有列:

    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 BYORDER BYHAVING 子句中使用。例如:

    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 table_references 子句指示从中检索行的表或表。如果您命名了多个表,则执行连接。有关连接语法的信息,请参阅 第 15.2.13.2 节,“连接子句”。对于每个指定的表,您可以选择性地指定别名。

    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_nametbl_name.col_name,或 db_name.tbl_name.col_name。您无需指定 tbl_namedb_name.tbl_name 前缀,除非引用可能会ambiguous。见 第 11.2.2 节,“标识符限定符”,以获取需要更明确的列引用形式的示例。

  • 表引用可以使用 tbl_name AS alias_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 BYGROUP 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 BYGROUP BYSELECT 中的列进行排序时,服务器使用初始字节数(由 max_sort_length 系统变量指定)对值进行排序。

  • MySQL 扩展了 GROUP BY 的使用,以允许选择未在 GROUP BY 子句中提到的字段。如果您没有从查询中获得预期的结果,请阅读 第 14.19 节“聚合函数” 中的 GROUP BY 描述。

  • HAVING 子句,类似于 WHERE 子句,指定选择条件。WHERE 子句指定选择列表中的列条件,但不能引用聚合函数。HAVING 子句指定组条件,通常由 GROUP BY 子句形成。查询结果仅包括满足 HAVING 条件的组。(如果没有 GROUP BY,所有行隐式形成一个聚合组。)

    HAVING 子句几乎在最后应用,即在将项目发送到客户端之前,且没有优化。(LIMITHAVING 之后应用。)

    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 BYHAVING 引用 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 BYHAVING 子句,它首先搜索 FROM 子句,然后搜索 select_expr 值。(对于 GROUP BYHAVING,这与 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 OFFSET offset 语法。

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

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

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

    您不能在 SELECT 语句中使用 FOR UPDATE,例如 CREATE TABLE new_table SELECT ... FROM old_table ...。(如果您尝试这样做,语句将被拒绝,错误信息为 无法更新表 'old_table',因为 'new_table' 正在被创建。)

    FOR SHARELOCK IN SHARE MODE 设置共享锁,允许其他事务读取检查的行,但不允许更新或删除它们。FOR SHARELOCK IN SHARE MODE 等同。然而,FOR SHARE,像 FOR UPDATE 一样,支持 NOWAITSKIP LOCKEDOF tbl_name 选项。FOR SHARELOCK IN SHARE MODE 的替代品,但 LOCK IN SHARE MODE 仍然可用,以保持向后兼容性。

    NOWAIT 使 FOR UPDATEFOR SHARE 查询立即执行,如果由于其他事务持有的锁无法获取行锁,则返回错误。

    SKIP LOCKED 导致 FOR UPDATEFOR SHARE 查询立即执行,排除结果集中的锁定行,这些行由另一个事务锁定。

    NOWAITSKIP LOCKED 选项对于基于语句的复制是不安全的。

    Note

    跳过锁定行的查询返回数据的不一致视图。SKIP LOCKED 因此不适合一般的事务工作。但是,它可以用于避免锁定争用,当多个会话访问同一个队列式表时。

    OF tbl_nameFOR UPDATEFOR SHARE 查询应用于命名表。例如:

    SELECT * FROM t1, t2 FOR SHARE OF t1 FOR UPDATE OF t2;

    OF tbl_name 被省略时,查询块中的所有表都将被锁定。因此,在不使用 OF tbl_name 的情况下,使用锁定子句与其他锁定子句组合将返回错误。指定同一个表在多个锁定子句中将返回错误。如果在 SELECT 语句中指定了别名作为表名,那么锁定子句只能使用别名。如果 SELECT 语句没有明确指定别名,那么锁定子句只能指定实际表名。

    有关 FOR UPDATEFOR SHARE 的更多信息,请参阅 第 17.7.2.4 节,“锁定读取”。有关 NOWAITSKIP LOCKED 选项的更多信息,请参阅 锁定读取并发性与 NOWAIT 和 SKIP LOCKED

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

  • 修饰符 ALLDISTINCT 指定是否返回重复行。ALL(默认) 指定返回所有匹配行,包括重复行。DISTINCT 指定从结果集中删除重复行。指定这两个修饰符将返回错误。DISTINCTROWDISTINCT 的同义词。

    DISTINCT 可以与使用 WITH ROLLUP 的查询一起使用。

  • HIGH_PRIORITYSELECT 语句的优先级高于更新表的语句。您应该仅将其用于非常快速的查询,必须立即执行。使用 HIGH_PRIORITY 查询语句时,如果表被锁定以供读取,将在更新语句等待表释放时执行。这仅影响使用表级锁定的存储引擎(例如 MyISAMMEMORYMERGE)。

    HIGH_PRIORITY 不能与 SELECT 语句一起使用,该语句是 UNION 的一部分。

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

    STRAIGHT_JOIN 不应用于优化器将其视为 constsystem 表的任何表。这样的表产生单行,在查询执行的优化阶段读取,并在查询执行之前将对其列的引用替换为相应的列值。这些表在 EXPLAIN 显示的查询计划中首先出现。见 第 10.8.1 节,“使用 EXPLAIN 优化查询”。这条例外可能不适用于 constsystem 表,它们用于外连接的 NULL 补充侧(即 LEFT JOIN 的右侧表或 RIGHT JOIN 的左侧表).

  • SQL_BIG_RESULTSQL_SMALL_RESULT 可以与 GROUP BYDISTINCT 一起使用,以告诉优化器结果集有很多行或很小,分别。对于 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 节,“信息函数”

    Note

    SQL_CALC_FOUND_ROWS 查询修饰符和伴随的 FOUND_ROWS() 函数已弃用;预计它们将在未来版本的 MySQL 中被删除。见 FOUND_ROWS() 的描述,以获取替代策略的信息。

  • 在 MySQL 8.3 之前,SQL_CACHESQL_NO_CACHE 修饰符用于查询缓存。查询缓存在 MySQL 8.3 中被删除。SQL_CACHE 修饰符也被删除。SQL_NO_CACHE 已弃用,且没有效果;预计它将在未来 MySQL 版本中被删除。