Documentation Home
MySQL 8.4 Reference Manual
Related Documentation Download this Manual
PDF (US Ltr) - 39.8Mb
PDF (A4) - 39.9Mb
Man Pages (TGZ) - 257.9Kb
Man Pages (Zip) - 364.9Kb
Info (Gzip) - 4.0Mb
Info (Zip) - 4.0Mb


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节,“连接子句”中描述。

  • 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 ...
  • tbl_name.* 可以用作qualified简写,来选择来自指定表的所有列:

    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_name 给定别名。别名用于表达式的列名,可以在 GROUP BYORDER BYHAVING 子句中使用。例如:

    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 table_references子句指示从哪些表中检索行。如果你命名多个表,你正在执行连接。关于连接语法,请见第15.2.13.2节,“JOIN Clause”。对于每个指定的表,您可以选择指定别名。

    tbl_name [[AS] alias] [index_hint]

    使用索引提示可以让优化器在查询处理时了解索引选择的信息。关于指定这些提示的语法,请见第10.9.4节,“Index Hints”

    您可以使用SET max_seeks_for_key=value作为强制MySQL优先选择键扫描而不是表扫描的alternative方法。见第7.1.8节,“Server System Variables”

  • 您可以在默认数据库中引用一个表为tbl_name,或为db_name.tbl_name指定数据库。您可以引用一个列为col_nametbl_name.col_name,或db_name.tbl_name.col_name。您不需要指定tbl_namedb_name.tbl_name前缀,除非引用将是歧义的。见第11.2.2节,“Identifier Qualifiers”,了解歧义的示例,该歧义需要更明确的列引用形式。

  • 表引用可以使用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;

    要以降序排序,添加DESC(降序)关键字到ORDER BY子句中排序的列名中。默认排序顺序是升序,可以使用ASC关键字来指定。

    如果ORDER BY在括号中出现,并且在外部查询中也应用于排序,结果是未定义的可能会在未来版本的MySQL中改变。

    使用列位置是弃用的,因为语法已经从SQL标准中删除。

  • 使用ORDER BYGROUP BY对排序的列在SELECT语句中排序时,服务器使用max_sort_length系统变量指定的初始字节数来排序值。

  • MySQL 扩展了GROUP BY的使用,允许选择未在GROUP BY子句中指定的列。如果您没有从查询中获取期望的结果,请阅读第14.19节,“聚合函数”的描述。

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

    HAVING子句在 nearly最后应用于客户端,且没有优化。(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 子句中解析未qualified 的列或别名引用,通过在 select_expr 值中搜索,然后在 FROM 子句中的表列中搜索。在 GROUP BYHAVING 子句中,它首先搜索 FROM 子句,然后搜索 select_expr 值。 (对于 GROUP BYHAVING,这与 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_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 Statement”

  • 如果您使用FOR UPDATE与存储引擎使用页或行锁定的存储引擎,查询中examined的行将在当前事务结束前保持写锁定状态。

    您不能将FOR UPDATE作为SELECT的一部分使用在语句中,如CREATE TABLE new_table SELECT ... FROM old_table ...。 (如果您尝试这样做,语句将被拒绝,并显示错误Can't update table 'old_table' while 'new_table' is being created。)

    FOR SHARELOCK IN SHARE MODE设置共享锁,使其他事务可以读取examined的行,但不能更新或删除它们。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_name 将对指定的表应用FOR 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节,“Locking Reads”。有关NOWAITSKIP LOCKED选项的更多信息,请见Locking Read Concurrency with NOWAIT and SKIP LOCKED

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

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

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

  • HIGH_PRIORITY将SELECT语句的优先级设置为更高,超过更新表的语句。您应该在非常快速的查询中使用该选项。使用SELECT 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 直接使用磁盘临时表,如果创建了临时表,并且优先使用排序而不是使用临时表。对于 SQL_SMALL_RESULT,MySQL 使用内存临时表来存储结果表,而不是使用排序。这通常不需要。

  • SQL_BUFFER_RESULT 强制结果被放入临时表。这有助于 MySQL 早释放表锁,并在将结果集发送到客户端时帮助。在使用 SQL_BUFFER_RESULT 时,需要在顶级 SELECT 语句中使用该语句,不可以在子查询或 UNION 中使用。

  • SQL_CALC_FOUND_ROWS 告诉 MySQL 计算结果集的行数,忽略任何 LIMIT 子句。然后,可以使用 SELECT FOUND_ROWS() 获取行数。见第14.15节,“信息函数”

    Note

    SQL_CALC_FOUND_ROWS

  • SQL_CACHE和SQL_NO_CACHE修饰符在MySQL 8.4之前与查询缓存一起使用。MySQL 8.4中删除了查询缓存。SQL_CACHE修饰符也被删除。SQL_NO_CACHE已经弃用,没有效果,预计将在未来的MySQL版本中删除。