13.2.9 SELECT 语法

如下内容均翻译自 MySQL 5.6 Reference Manual 来自一个四级都还没过的渣渣 经过阅读官方文档加深对一些sql注入的理解mysql

13.2.9.1 SELECT ... INTO Syntax
13.2.9.2 JOIN Syntax
13.2.9.3 UNION Syntaxsql

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 ...]
    [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 OUTFILE 'file_name'
        [CHARACTER SET charset_name]
        export_options
      | INTO DUMPFILE 'file_name'
      | INTO var_name [, var_name]]
    [FOR UPDATE | LOCK IN SHARE MODE]]

SELECT用于从一个或多个表中取回行,能够包含UNION语句和子查询。参见第13.2.9.3节,UNION语法,和第13.2.10节,Subquery语法。数据库

SELECT语句最经常使用的子句是:缓存

  • 每一个select_expr指示要检索的列。 必须至少有一个select_expr。服务器

  • table_references指示要从中检索行的一个或多个表。 其语法在第13.2.9.2节“JOIN语法”中描 述。函数

  • SELECT支持使用partition关键字进行显式分区选择,在table_reference中的表名后面有一个分区或子分区列表(或二者都有)(请参见第13.2.9.2节“联接语法”)。在这种状况下,只从列出的分区中选择行,而忽略表中的任何其余分区。有关更多信息和示例,请参见第19.5节“分区选择”。优化

  • SELECT ... PARTITION from tables using storage engines such as MyISAM that perform table-level locks (and thus partition locks) lock only the partitions or subpartitions named by the PARTITION option.翻译

    For more information, see Section 19.6.4, “Partitioning and Locking”.code

  • WHERE子句(若是给定)指示要选择行必须知足的一个或多个条件。where_condition是一个表达式,对于要选择的每一行,其计算结果为true。若是没有WHERE子句,该语句将选择全部行。orm

    在WHERE表达式中,您可使用MySQL支持的任何函数和运算符,聚合(摘要)函数除外。参见第9.5节“表达式”和第12章“函数和运算符”。

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子句能够如语法描述中所示出现,也能够紧跟在select_expr列表以后出现。 有关INTO的更多信息,请参见第13.2.9.1节“SELECT ... INTO语法”。

select_expr列表术语包含选择列表,该列表指示要检索哪些列。术语指定列或表达式,或者可使用 * 来简写

  • 一个只包含一个非限定 * 的选择列表能够用做从全部表中选择全部列的简写

    SELECT * FROM t1 INNER JOIN t2 ...
  • tbl_name.* 可用做限定简写,从指定表中选择全部列:

    SELECT t1.*, t2.* FROM t1 INNER JOIN t2 ...
  • 与选择列表中的其余项一块儿使用非限定可能会产生解析错误。为了不这个问题,请使用限定的tbl_name。引用

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

如下内容提供了有关其余SELECT子句的附加信息:

  • 可使用 AS alias_nameselect expr提供别名。别名用做表达式的列名,能够在GROUP BYORDER BYHAVING子句中使用。例如

    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.4.4.4节,列别名的问题。
  • FROM table_references子句指示从中检索行的一个或多个表。若是您指定了多个表,则表示您正在执行JOIN。有关JOIN语法的信息,请参见13.2.9.2节“JOIN语法”。对于指定的每一个表,您能够选择指定别名。

    tbl_name [[AS] alias] [index_hint]

    index_hint的使用为优化器提供了关于如何在查询处理过程当中选择索引的信息。有关指定这些提示的语法描述,请参见第8.9.3节“索引提示”。

    您可使用SET max seek for key=value做为另外一种强制MySQL选择键扫描而不是表扫描的方法。参见第5.1.7节,服务器系统变量。
  • 您能够将缺省数据库中的表称为tbl_name,或将db_name.tbl_name称为显式指定数据库。 您能够将列引用为col_nametbl_name.col_namedb_name.tbl_name.col_name。 除非引用不明确,不然无需为列引用指定tbl_namedb_name.tbl_name前缀。 有关须要更明确的列引用形式的歧义的示例,请参见第9.2.1节“标识符限定符”。
  • 引用表时可使用 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出如今子查询中而且也应用于外部查询,则最外面的ORDER BY优先。例如,如下语句的结果按降序排列,而不是升序排列:

    (SELECT ... ORDER BY a) ORDER BY a DESC;
    不建议使用列位置,由于该语法已从SQL标准中删除。
  • MySQL扩展了GROUP BY子句,所以您还能够在子句中指定的列以后指定ASCDESC

    SELECT a, COUNT(b) FROM test_table GROUP BY a DESC;
  • 若是使用GROUP BY,输出行将根据GROUP BY列进行排序,就好像对相同的列都有一个ORDER BY同样。为了不GROUP BY排序产生的开销,请添加ORDER BY NULL

    SELECT a, COUNT(b) FROM test_table GROUP BY a ORDER BY NULL;
    不同意依赖隐式GROUP BY排序(即,在没有ASC或DESC指示符的状况下进行排序)。要生成给定的排序顺序,请为“GROUP BY”列使用显式的ASC或DESC指示符,或者提供ORDER BY子句。
  • 当您使用ORDER BY或GROUP BY对SELECT中的列进行排序时,服务器仅使用max_sort_length系统变量指示的初始字节数对值进行排序。
  • MySQL扩展了GROUP BY的使用,容许选择GROUP BY子句中未说起的字段。 若是您没有从查询中得到预期的结果,请阅读第12.19节“聚合(GROUP BY)函数”中的GROUP BY说明。
  • GROUP BY容许WITH ROLLUP修饰符。 请参见第12.19.2节“GROUP BY Modifiers”。
  • 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列中的列名。
  • 不要对应该出如今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使用不一样的名称。
  • MySQL经过搜索select_expr值,而后在FROM子句中的表的列中搜索ORDER BY子句中的非限定列或别名引用。 对于GROUP BY或HAVING子句,它在搜索select_expr值以前搜索FROM子句。 (对于GROUP BY和have,这与mysql 5.0以前的行为不一样,后者使用与ORDER BY相同的规则。)
  • LIMIT子句可用于约束SELECT语句返回的行数。LIMIT接受一个或两个数值参数,除了这些例外,它们都必须是非负整数常量

    • 在prepared statements中,LIMIT参数可使用?占位符标记。
    • 在stored programs中,LIMIT参数可使用integer-valued routine parameters或局部变量来指定。
      使用两个参数,第一个参数指定要返回的第一行的偏移量,第二个参数指定要返回的最大行数。第一行的偏移量是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。

    对于prepared statements,可使用占位符。下面的语句将从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出如今子查询中而且也应用于外部查询,则最外面的LIMIT优先。例如,如下语句产生两行,而不是一行:

    (SELECT ... LIMIT 1) LIMIT 2;
  • PROCEDURE子句指定应处理结果集中数据的过程。 有关示例,请参见第8.4.2.4节“使用PROCEDURE ANALYZE”,其中介绍了ANALYZE,该过程可用于获取可能有助于减少表大小的最佳列数据类型的建议。

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

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

  • 若是对使用页锁或行锁的存储引擎使用FOR UPDATE,则查询检查的行将被写入锁定,直到当前事务结束。 使用LOCK IN SHARE MODE设置共享锁,容许其余事务读取已检查的行,但不容许更新或删除它们。 请参见第14.7.2.4节“锁定读取”。

    此外,您不能在诸如CREATE TABLE new_table SELECT ... FROM old_table ....之类的语句中使用FOR UPDATE做为SELECT的一部分。(若是您尝试这样作,语句将被拒绝,并显示错误 Can't update table 'old_table' while 'new_table' is being created.)这是MySQL 5.5及更早版本的行为更改,它容许CREATE TABLE ... SELECT语句在正在建立的表以外的表中进行更改。

在SELECT关键字以后,您可使用许多影响语句操做的修饰符。 HIGH_PRIORITY(高优先级),STRAIGHT_JOIN(直链接)和以SQL_开头的修饰符是标准SQL的MySQL扩展。

  • ALLDISTINCT修饰符指定是否应返回重复的行。 ALL(默认值)指定应返回全部匹配的行,包括重复行。 DISTINCT指定从结果集中删除重复的行。 同时指定两个修饰符是错误的。 DISTINCTROW是DISTINCT的同义词。
  • 高优先级赋予SELECT比更新表的语句更高的优先级。您应该只将它用于很是快速且必须当即完成的查询。即便有更新语句等待表释放,在表被锁定读取时发出的SELECT HIGH_PRIORITY查询也会运行。这仅影响仅使用表级锁定的存储引擎(如MyISAM、MEMORY和MERGE)。

    HIGH_PRIORITY不能与属于UNION的SELECT语句一块儿使用。
  • STRAIGHT _ JOIN强制优化器按照表在FROM子句中列出的顺序来链接表。若是优化器以非最佳顺序链接表,您可使用它来加速查询。还能够在table_references列表中使用STRAIGHT _ JOIN。参见第13.2.9.2节“链接语法”。

    STRAIGHT_JOIN不适用于优化程序视为const或system的任何表。 这样的表生成单行,在查询执行的优化阶段读取,而且在查询执行进行以前用适当的列值替换对其列的引用。 这些表将首先出如今EXPLAIN显示的查询计划中。 请参见第8.8.1节“使用EXPLAIN优化查询”。 此异常可能不适用于在外链接的NULL补充端(即LEFT JOIN的右侧表或RIGHT JOIN的左侧表)上使用的const或系统表。
  • SQL_BIG_REQUESTSQL_SMAll_REQUEST能够与GROUP BY或DISTINCT一块儿使用,分别告诉优化器结果集有许多行或很小。对于SQL_BIG_REQUEST,若是建立了基于磁盘的临时表,MySQL会直接使用它们,而且更喜欢使用临时表中在GROUP BY元素里的键进行排序。 对于SQL_SMALL_RESULT,MySQL使用内存中的临时表来存储生成的表而不是使用排序。 一般不须要这样作。
  • SQL_BUFFER_RESULT强制将结果放入临时表中。 这有助于MySQL尽早释放表锁,并在须要很长时间将结果集发送到客户端的状况下提供帮助。 此修饰符只能用于顶级SELECT语句,不能用于子查询或UNION以后。
  • SQL_CALC_FOUND_ROWS告诉MySQL计算结果集中将有多少行,忽略任何LIMIT子句。 而后可使用SELECT FOUND_ROWS()检索行数。 请参见第12.15节“信息功能”。
  • SQL_CACHESQL_NO_CACHE修饰符会影响查询缓存中查询结果的缓存(请参见第8.10.3节“MySQL查询缓存”)。 SQL_CACHE告诉MySQL将结果存储在查询缓存中(若是它是可缓存的,而且query_cache_type系统变量的值是2或DEMAND)。 使用SQL_NO_CACHE,服务器不使用查询缓存。 它既不检查查询缓存,也不检查结果是否已缓存,也不缓存查询结果。 (因为解析器中的限制,空格字符必须位于SQL_NO_CACHE关键字以前和以后;非空格(如换行符)会致使服务器检查查询缓存以查看结果是否已缓存。)

    这两个修饰符是互斥的,若是同时指定它们则会发生错误。 此外,子查询(包括FROM子句中的子查询)和第一个SELECT之外的联合中的SELECT语句不容许使用这些修饰符。

    对于视图,若是SQL_NO_CACHE出如今查询中的任何SELECT中,则适用。 对于可高速缓存的查询,若是SQL_CACHE出如今查询引用的视图的第一个SELECT中,则应用SQL_CACHE。

使用存储引擎从分区表中进行选择,例如使用表级锁的MyISAM,只锁定那些包含与SELECT语句WHERE子句匹配的行的分区。(使用行级锁定的存储引擎(如InnoDB)不会出现这种状况。)有关更多信息,请参见第19.6.4节“分区和锁定”。

相关文章
相关标签/搜索