### 13.2.10 SELECT 语句

[13.2.10.1 SELECT ... INTO 语句](select-into.html)
[13.2.10.2 JOIN 子句](join.html)
[13.2.10.3 UNION 子句](union.html)
[13.2.10.4 带括号的查询表达式](parenthesized-query-expressions.html)

[](<>)

```
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.html)用于检索从一个或多个表中选择的行，并且可以包括[`联盟`](union.html)语句和子查询。看[第 13.2.10.3 节，“联合条款”](union.html)， 和[第 13.2.11 节，“子查询”](subqueries.html).一种[`选择`](select.html)语句可以以 a 开头[`和`](with.html)子句定义可在[`选择`](select.html).看[第 13.2.15 节，“WITH（公用表表达式）”](with.html).

最常用的从句[`选择`](select.html)陈述是这些：

-   每个*`选择表达式`*表示要检索的列。必须至少有一个*`选择表达式`*.

-   *`表参考`*指示要从中检索行的一个或多个表。它的语法在[第 13.2.10.2 节，“JOIN 子句”](join.html).

-   `选择`支持使用显式分区选择`划分`子句中的表名后面有一个分区或子分区（或两者）列表*`表参考`*（看[第 13.2.10.2 节，“JOIN 子句”](join.html)）。在这种情况下，仅从列出的分区中选择行，而忽略表的任何其他分区。有关更多信息和示例，请参阅[第 24.5 节，“分区选择”](partitioning-selection.html).

-   这`在哪里`子句（如果给定）指示选择行必须满足的一个或多个条件。*`where_condition`*是一个表达式，对于要选择的每一行，其计算结果都为真。如果没有，该语句选择所有行`在哪里`条款。

    在里面`在哪里`表达式，您可以使用 MySQL 支持的任何函数和运算符，聚合（组）函数除外。看[第 9.5 节，“表达式”](expressions.html)， 和[第 12 章，*函数和运算符*](functions.html).

[`选择`](select.html)也可用于检索不参考任何表的计算行。

例如：

```
mysql> SELECT 1 + 1;
        -> 2
```

[](<>)您可以指定`双重的`在没有引用表的情况下作为虚拟表名：

```
mysql> SELECT 1 + 1 FROM DUAL;
        -> 2
```

`双重的`纯粹是为了方便需要所有[`选择`](select.html)语句应该有`从`可能还有其他条款。MySQL 可能会忽略这些子句。MySQL 不需要`从双`如果没有引用表。

一般来说，使用的子句必须完全按照语法描述中显示的顺序给出。例如，一个`拥有`子句必须在任何`通过...分组`子句和任何之前`订购方式`条款。这`进入`子句（如果存在）可以出现在语法描述指示的任何位置，但在给定语句中只能出现一次，而不是多个位置。有关更多信息`进入`， 看[第 13.2.10.1 节，“SELECT ... INTO 语句”](select-into.html).

名单*`选择表达式`*terms 包括指示要检索哪些列的选择列表。术语指定列或表达式或可以使用`*`-速记：

-   仅包含一个不合格的选择列表`*`可以用作从所有表中选择所有列的简写：

    ```
    SELECT * FROM t1 INNER JOIN t2 ...
    ```

-   `*`tbl_name`*.*`可以用作合格的速记来从命名表中选择所有列：

    ```
    SELECT t1.*, t2.* FROM t1 INNER JOIN t2 ...
    ```

-   如果一个表有不可见的列，`*`和`*`tbl_name`*.*`不包括它们。要包含在内，必须明确引用不可见的列。

-   使用不合格`*`选择列表中的其他项目可能会产生解析错误。为避免此问题，请使用合格的`*`tbl_name`*.*`参考：

    ```
    SELECT AVG(score), t1.* FROM t1 ...
    ```

    以下列表提供了有关其他`选择`条款：

-   [](<>) [](<>)一种*`选择表达式`*可以使用给定别名`作为 *`别名`*`.别名用作表达式的列名，可用于`通过...分组`,`订购方式`， 要么`拥有`条款。例如：

    ```
    SELECT CONCAT(last_name,', ',first_name) AS full_name
      FROM mytable ORDER BY full_name;
    ```

    这`作为`别名时关键字是可选的*`选择表达式`*带有标识符。前面的例子可以这样写：

    ```
    SELECT CONCAT(last_name,', ',first_name) full_name
      FROM mytable ORDER BY full_name;
    ```

    然而，由于`作为`是可选的，如果您忘记了两个之间的逗号，可能会出现一个微妙的问题*`选择表达式`*表达式：MySQL 将第二个解释为别名。例如，在以下语句中，`专栏b`被视为别名：

    ```
    SELECT columna columnb FROM mytable;
    ```

    因此，养成使用的习惯是一个好习惯`作为`明确指定列别名时。

    不允许在 a 中引用列别名`在哪里`子句，因为当`在哪里`子句被执行。看[第 B.3.4.4 节，“列别名问题”](problems-with-alias.html).

-   [](<>) [](<>)这`从 *`表参考`*`子句指示要从中检索行的一个或多个表。如果您命名多个表，则表示您正在执行连接。有关连接语法的信息，请参阅[第 13.2.10.2 节，“JOIN 子句”](join.html).对于每个指定的表，您可以选择指定一个别名。

    ```
    tbl_name [[AS] alias] [index_hint]
    ```

    [](<>)[](<>)

    索引提示的使用为优化器提供了有关如何在查询处理期间选择索引的信息。有关指定这些提示的语法说明，请参阅[第 8.9.4 节，“索引提示”](index-hints.html).

    您可以使用`SET max_seeks_for_key=*`价值`*`作为强制 MySQL 更喜欢键扫描而不是表扫描的替代方法。看[第 5.1.8 节，“服务器系统变量”](server-system-variables.html).

-   您可以将默认数据库中的表称为*`tbl_name`*，或作为*`数据库名称`*.*`tbl_name`*明确指定数据库。您可以将列称为*`col_name`*,*`tbl_name`*.*`col_name`*， 要么*`数据库名称`*.*`tbl_name`*.*`col_name`*.您无需指定*`tbl_name`*要么*`数据库名称`*.*`tbl_name`*列引用的前缀，除非引用不明确。看[第 9.2.2 节，“标识符限定符”](identifier-qualifiers.html)，对于需要更明确的列引用形式的歧义示例。

-   [](<>) [](<>)表引用可以使用别名`*`tbl_name`* 作为 *`别名`*`要么*`tbl_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;
    ```

-   [](<>)为输出选择的列可以参考`订购方式`和`通过...分组`使用列名、列别名或列位置的子句。列位置是整数并以 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`（降序）关键字到列中的名称`订购方式`您排序的子句。默认为升序；这可以使用显式指定`ASC`关键词。

    如果`订购方式`出现在带括号的查询表达式中，也应用于外部查询，结果是未定义的，并且可能在 MySQL 的未来版本中发生变化。

    不推荐使用列位置，因为该语法已从 SQL 标准中删除。

-   [](<>)在 MySQL 8.0.13 之前，MySQL 支持允许显式的非标准语法扩展`ASC`要么`DESC`代号为`通过...分组`列。MySQL 8.0.12 及更高版本支持`订购方式`具有分组功能，因此不再需要使用此扩展。（错误 #86312、错误 #26073525）这也意味着您可以在使用时对任意列或列进行排序`通过...分组`， 像这样：

    ```
    SELECT a, b, COUNT(c) AS t FROM test_table GROUP BY a,b ORDER BY a,t DESC;
    ```

    从 MySQL 8.0.13 开始，`通过...分组`不再支持扩展：`ASC`要么`DESC`代号为`通过...分组`列是不允许的。

-   [](<>) [](<>)当你使用`订购方式`要么`通过...分组`对 a 中的列进行排序[`选择`](select.html)，服务器仅使用由[`最大排序长度`](server-system-variables.html#sysvar_max_sort_length)系统变量。

-   MySQL 扩展了使用`通过...分组`允许选择未在`通过...分组`条款。如果您没有从查询中获得预期的结果，请阅读`通过...分组`在发现[第 12.20 节，“聚合函数”](aggregate-functions-and-modifiers.html).

-   `通过...分组`允许一个`带汇总`修饰符。看[第 12.20.2 节，“GROUP BY 修饰符”](group-by-modifiers.html).

    [](<>)以前是不允许使用的`订购方式`在具有`带汇总`修饰符。自 MySQL 8.0.12 起，此限制已解除。看[第 12.20.2 节，“GROUP BY 修饰符”](group-by-modifiers.html).

-   这`拥有`子句，如`在哪里`子句，指定选择条件。这`在哪里`子句对选择列表中的列指定条件，但不能引用聚合函数。这`拥有`子句指定组的条件，通常由`通过...分组`条款。查询结果只包括满足`拥有`状况。（如果不`通过...分组`存在时，所有行都会隐式形成一个聚合组。）

    这`拥有`子句几乎在最后应用，就在项目发送到客户端之前，没有优化。(`限制`后应用`拥有`.)

    [](<>)

    SQL 标准要求`拥有`必须只引用`通过...分组`聚合函数中使用的子句或列。然而，MySQL 支持对这种行为的扩展，并允许`拥有`引用列中的[`选择`](select.html)外部子查询中的列表和列。

    如果`拥有`子句指的是不明确的列，会出现警告。在下面的声明中，`col2`是模棱两可的，因为它既用作别名又用作列名：

    ```
    SELECT COUNT(col1) AS col2 FROM t GROUP BY col2 HAVING col2 = 2;
    ```

    优先考虑标准 SQL 行为，因此如果`拥有`列名同时用于`通过...分组`并且作为选择列列表中的别名列，优先选择列中的列`通过...分组`柱子。

-   不使用`拥有`对于应该在`在哪里`条款。例如，不要写以下内容：

    ```
    SELECT col_name FROM tbl_name HAVING col_name > 0;
    ```

    改为这样写：

    ```
    SELECT col_name FROM tbl_name WHERE col_name > 0;
    ```

-   这`拥有`子句可以引用聚合函数，其中`在哪里`子句不能：

    ```
    SELECT user, MAX(salary) FROM users
      GROUP BY user HAVING MAX(salary) > 10;
    ```

    （这在某些旧版本的 MySQL 中不起作用。）

-   MySQL 允许重复的列名。也就是说，可以有多个*`选择表达式`*同名。这是对标准 SQL 的扩展。因为 MySQL 也允许`通过...分组`和`拥有`参考*`选择表达式`*值，这可能会导致歧义：

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

    在该语句中，两列都有名称`一种`.为确保使用正确的列进行分组，请为每个列使用不同的名称*`选择表达式`*.

-   这`窗户`子句（如果存在）定义可以由窗口函数引用的命名窗口。有关详细信息，请参阅[第 12.21.4 节，“命名窗口”](window-functions-named-windows.html).

-   MySQL 解析不合格的列或别名引用`订购方式`通过在子句中搜索*`选择表达式`*值，然后在表的列中`从`条款。为了`通过...分组`要么`拥有`子句，它搜索`从`在搜索之前的子句*`选择表达式`*价值观。（为了`通过...分组`和`拥有`，这与使用相同规则的 MySQL 5.0 之前的行为不同`订购方式`.)

-   [](<>)这`限制`子句可用于限制返回的行数[`选择`](select.html)陈述。`限制`接受一个或两个数字参数，它们都必须是非负整数常量，但以下情况除外：

    -   在准备好的陈述中，`限制`可以使用指定参数`?`占位符标记。

    -   在存储的程序中，`限制`可以使用整数值的例程参数或局部变量来指定参数。

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

    换一种说法，`限制 *`行数`*`相当于`限制 0, *`行数`*`.

    对于准备好的语句，您可以使用占位符。以下语句从`表`桌子：

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

    以下语句从第 2 行到第 6 行返回`表`桌子：

    ```
    SET @skip=1; SET @numrows=5;
    PREPARE STMT FROM 'SELECT * FROM tbl LIMIT ?, ?';
    EXECUTE STMT USING @skip, @numrows;
    ```

    为了与 PostgreSQL 兼容，MySQL 还支持`限制 *`行数`* 抵消 *`抵消`*`句法。

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

-   这[`选择...进入`](select-into.html)的形式[`选择`](select.html)允许将查询结果写入文件或存储在变量中。有关详细信息，请参阅[第 13.2.10.1 节，“SELECT ... INTO 语句”](select-into.html).

-   [](<>) [](<>) [](<>) [](<>) [](<>)如果你使用`更新`对于使用页锁或行锁的存储引擎，查询检查的行会被写锁定，直到当前事务结束。

    你不能使用`更新`作为一部分[`选择`](select.html)在诸如[`创建表 *`新表`* 选择 ... 从 *`旧表`* ...`](create-table-select.html).（如果您尝试这样做，该语句将被拒绝并出现错误 Can't update table '*`旧表`*' 尽管 '*`新表`*' 正在创建中。）

     `分享`和`锁定分享模式`设置共享锁，允许其他事务读取检查的行，但不能更新或删除它们。`分享`和`锁定分享模式`是等价的。然而，`分享`， 喜欢`更新`, 支持`现在等待`,`跳过锁定`， 和`的 *`tbl_name`*`选项。`分享`是替代品`锁定分享模式`， 但`锁定分享模式`仍然可用于向后兼容。

     `现在等待`导致`更新`要么`分享`查询立即执行，如果由于另一个事务持有锁而无法获得行锁，则返回错误。

     `跳过锁定`导致`更新`要么`分享`立即执行的查询，不包括结果集中被另一个事务锁定的行。

     `现在等待`和`跳过锁定`对于基于语句的复制，选项是不安全的。

    笔记

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

     `的 *`tbl_name`*`适用`更新`和`分享`对命名表的查询。例如：

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

    查询块引用的所有表在`的 *`tbl_name`*`被省略。因此，使用锁定子句而不`的 *`tbl_name`*`与另一个锁定子句结合使用会返回错误。在多个锁定子句中指定同一个表会返回错误。如果一个别名被指定为表名`选择`语句，锁定子句只能使用别名。如果`选择`语句没有显式指定别名，锁定子句可能只指定实际的表名。

    有关更多信息`更新`和`分享`， 看[第 15.7.2.4 节，“锁定读取”](innodb-locking-reads.html).有关更多信息`现在等待`和`跳过锁定`选项，见[使用 NOWAIT 和 SKIP LOCKED 锁定读取并发](innodb-locking-reads.html#innodb-locking-reads-nowait-skip-locked).

    继[`选择`](select.html)关键字，您可以使用一些影响语句操作的修饰符。`HIGH_PRIORITY`,`STRAIGHT_JOIN`, 和以`SQL_`是标准 SQL 的 MySQL 扩展。

-   这`全部`和`清楚的`修饰符指定是否应返回重复的行。`全部`（默认值）指定应返回所有匹配的行，包括重复行。`清楚的`指定从结果集中删除重复行。指定两个修饰符是错误的。`区别`是同义词`清楚的`.

    在 MySQL 8.0.12 及更高版本中，`清楚的`可以与也使用的查询一起使用`带汇总`.（错误 #87450、错误 #26640100）

    [](<>)[](<>)[](<>)

-   `HIGH_PRIORITY`给出了[`选择`](select.html)比更新表的语句具有更高的优先级。您应该仅将其用于非常快速且必须立即完成的查询。一种`选择 HIGH_PRIORITY`即使有更新语句等待表空闲，在锁定表以供读取时发出的查询也会运行。这仅影响仅使用表级锁定的存储引擎（例如`MyISAM`,`记忆`， 和`合并`）。

    [](<>)

    `HIGH_PRIORITY`不能与[`选择`](select.html)作为 a 的一部分的语句[`联盟`](union.html).

-   `STRAIGHT_JOIN`强制优化器按照它们在`从`条款。如果优化器以非最佳顺序连接表，您可以使用它来加快查询速度。`STRAIGHT_JOIN`也可以用在*`表参考`*列表。看[第 13.2.10.2 节，“JOIN 子句”](join.html).

    [](<>)[](<>)[](<>)

    `STRAIGHT_JOIN`不适用于优化器视为[`常量`](explain-output.html#jointype_const)要么[`系统`](explain-output.html#jointype_system)桌子。这样的表产生单行，在查询执行的优化阶段被读取，并且在查询执行继续之前，对其列的引用被替换为适当的列值。这些表首先出现在由[`解释`](explain.html).看[第 8.8.1 节，“使用 EXPLAIN 优化查询”](using-explain.html).此例外可能不适用于[`常量`](explain-output.html#jointype_const)要么[`系统`](explain-output.html#jointype_system)上使用的表`空值`- 外连接的补边（即，右表）`左连接`或 a 的左侧表`正确加入`.

-   `SQL_BIG_RESULT`要么`SQL_SMALL_RESULT`可以与`通过...分组`要么`清楚的`分别告诉优化器结果集有很多行或很小。为了`SQL_BIG_RESULT`，如果创建了基于磁盘的临时表，MySQL 直接使用它们，并且更喜欢排序而不是使用带有键的临时表`通过...分组`元素。为了`SQL_SMALL_RESULT`, MySQL 使用内存中的临时表来存储结果表，而不是使用排序。这通常不需要。

    [](<>)[](<>)

-   `SQL_BUFFER_RESULT`强制将结果放入临时表中。这有助于 MySQL 及早释放表锁，并在需要很长时间才能将结果集发送到客户端的情况下提供帮助。此修饰符只能用于顶级[`选择`](select.html)语句，不适用于子查询或后续[`联盟`](union.html).

    [](<>)

-   `SQL_CALC_FOUND_ROWS`告诉 MySQL 计算结果集中有多少行，忽略任何`限制`条款。然后可以使用检索行数`选择 FOUND_ROWS()`.看[第 12.16 节，“信息功能”](information-functions.html).

    笔记

    这`SQL_CALC_FOUND_ROWS`查询修饰符和伴随[`FOUND_ROWS()`](information-functions.html#function_found-rows)自 MySQL 8.0.17 起，函数已弃用；期望它们在 MySQL 的未来版本中被删除。见[`FOUND_ROWS()`](information-functions.html#function_found-rows)有关替代策略的信息的描述。

    [](<>)

-   这`SQL_CACHE`和`SQL_NO_CACHE`在 MySQL 8.0 之前，修饰符与查询缓存一起使用。MySQL 8.0 中删除了查询缓存。这`SQL_CACHE`修饰符也被删除。`SQL_NO_CACHE`已弃用，并且没有效果；期望它在未来的 MySQL 版本中被删除。

    [](<>)[](<>)
