MySQL SELECT语法(一)SELECT语法详解
源自MySQL 5.7 官方手册:13.2.9 SELECT Syntax
SELECT的语法如下:
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解析
SELECT用于从一个或者多个表中取回数据行,也可以包括UNION语句和子查询。UNION语句参考后续文章,而子查询在手册13.2.10节。
SELECT语句最常用的子句有这些:
- 每个select_expr指示要检索的列。所以必须至少有一个select_expr。
- table_references指示要从中取回行数据的一个或多个表。其语法在第13.2.9.2节“JOIN语法”中描述。
- SELECT支持使用PARTITION显式分区选择,其中包含table_reference中表的名称后面的分区或子分区(或两者)列表。关于分区的更多信息在Section 22.6.4, “Partitioning and Locking”
- 如果存在WHERE子句,其中的条件对行数据进行筛选。where_condition是一个表达式,对于要选择的每一行,其计算结果为true。如果没有WHERE子句,该语句将选择所有行。在WHERE表达式中,您可以使用除聚合函数之外的任何MySQL支持的函数和运算符。See Section 9.5, “Expressions”, and Chapter 12, Functions and Operators.
SELECT也可用于检索计算的行而不引用任何表。
mysql> SELECT 1 + 1;
-> 2
在没有引用表的情况下,允许将DUAL指定为虚拟表名:
mysql> SELECT 1 + 1 FROM DUAL;
-> 2
DUAL的存在只是为了方便。MySQL可能会忽略这些子句。如果没有引用表,MySQL不需要FROM DUAL。
通常,使用的子句必须完全按照语法描述中展示的顺序给出。
例如,HAVING子句必须位于任何GROUP BY子句之后和任何ORDER BY子句之前。例外情况是INTO子句可以如语法描述中所示出现,也可以紧跟在select_expr列表之后出现。SELECT...INTO后续文章会讲。
select_expr项列表包括了要取回的列,该项可以指定一个字段、一个表达式或者使用*号。
- SELECT列表中只包含一个*号,即非限定*,意味着从所有表中取回所有的列。
- 而tb.*,限定*,表示取回一个指定表中的所有列。
- 在SELECT列表中使用非限定的*,可能会产生解析错误。要注意使用场合,
二、关于SELECT子句的一些附加知识:
2.1
可以使用AS alias_name为select_expr指定别名。别名用作表达式的列名,可用于GROUP BY,ORDER BY或HAVING子句。
AS关键字是可选项,在指定列的别名时养成使用AS是一种好习惯。
MySQL不允许在WHERE子句中引用列的别名,因为当WHERE子句执行时,列值可能还尚未确定。See Section B.4.4.4, “Problems with Column Aliases”.
2.2
FROM后的table_references指示参与查询的一个或者多个表。如果列出了多个表,就会执行JOIN操作。而对于每一个指定表,都可以为其定义别名。
tbl_name [[AS] alias] [index_hint]
使用index_hint,会为优化器提供有关如何在查询处理期间选择索引的信息。关于它,see Section 8.9.4, “Index Hints”。
当然,也可以使用SET max_seeks_for_key = value作为替代方法,强制MySQL更优先使用键扫描而不是表扫描。See Section 5.1.7, “Server System Variables”
2.3
不使用AS也能为表定义别名,直接空格后填写即可。
2.4
SELECT后被选择的列,可以在ORDER IN和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;
如果ORDER BY出现在子查询中,并且也应用于外部查询,则最外层的ORDER BY优先。
例如,以下语句的结果按降序排序,而不是按升序排序:
(SELECT ... ORDER BY a) ORDER BY a DESC;
不推荐使用代表列位置的数字的方法,因为这已经从标准SQL中删除。
2.5
如果使用了GROUP BY,被分组的列会自动按升序排列(就好像有一个ORDER BY语句后面跟了同样的列)。如果要避免GROUP BY因为自动排序生成的开销,添加ORDER BY NULL可以解决:
SELECT a, COUNT(b) FROM test_table GROUP BY a ORDER BY NULL;
虽然在GROUP BY语句上也有一些对字段指定排序的用法,但是他们现在都已经被抛弃。正确的做法是,使用ORDER BY子句来进行排序。
2.6
当使用ORDER BY或GROUP BY对SELECT中的列进行排序时,服务器仅使用max_sort_length系统变量指示的初始字节数对值进行排序。
2.7
MySQL扩展了GROUP BY的用法,它允许在Select列表中出现没有在GROUP BY中进行分组的字段。这点在前面的聚合函数的文章中已经讲得很清楚。
2.8
GROUP BY子句允许添加WITH ROLLUP修饰符
2.9
Having子句一般应用在最后,恰好在结果集被返回给MySQL客户端前,且没有进行优化。(而LIMIT应用在HAVING后)
SQL标准要求:HAVING必须引用在GROUP BY列表中或者聚合函数使用的列。然而,MySQL对此进行了扩展,它允许HAVING引用Select子句列表中的列,还有外部子查询的列。
如果HAVING引用的列具有歧义,会有警告产生。下面的语句中,col2具有歧义:
SELECT COUNT(col1) AS col2 FROM t GROUP BY col2 HAVING col2 = 2;
这里没报错只有警告是为什么呢?因为MySQLS虽然对标准SQL进行了扩展,但是在这种情况下,标准SQL的选择具有优先权。即MySQL把HAVING中的col2优先指向GROUP BY中的col2。
2.11
切记不要在该使用WHERE的地方使用HAVING。HAVING是和GROUP BY搭配的。
2.12
HAVING子句可以引用聚合函数,而WHERE不能。
SELECT user, MAX(salary) FROM users
GROUP BY user HAVING MAX(salary) > 10;
上面的查询在老版本的MySQL可能无效。
2.13
MySQL允许重复的列名。也就是说,同名的select_expr可以有多个。这是对标准SQL的扩展。而因为MySQL允许GROUP BY和HAVING引用select_expr值,这可能会引起歧义:
SELECT 12 AS a, a FROM t GROUP BY a;
在这个语句中,两个列都名为a(实际应该是不同)。(着应该是被允许的)
那么为了不引起歧义以对正确的列进行分组,切记对select_expr使用不同的别名。
2.14
对于ORDER BY子句中的非限定列或别名引用,MySQL是这样进行解析的:先搜索SELECT子句列表中的select_expr值,然后在FROM后的表中的列。
而对于GROUP BY和HAVING子句中的非限定列或别名,MySQL先搜索FROM子句,再搜索SELECT子句。
2.15
LIMIT子句可用于约束SELECT语句返回的行数。
LIMIT可以有一个或者两个参数,都必须为非负整数。
但是也有例外情况:
- 在预编译的语句中,LIMIT参数可以使用占位符标记——“?” 进行指定。
- 在存储的程序(存储过程?)中,可以使用整数值例程参数(integer-valued routine parameters)或局部变量指定LIMIT参数。
若LIMIT有两个参数,第一个指定相对于第一行的偏移量,第二个参数指定应该返回的行数。第一行自己的偏移量是0,而不是1:
/*取回结果集中的6~15行*/
SELECT * FROM tbl LIMIT 5,10;
那如果要取回一个设定某个偏移量之后的所有行,可以为第二参数设定一个非常大的常量。以下查询取回从第96行起的所有数据:
SELECT * FROM tbl LIMIT 95,18446744073709551615;
若LIMIT只有一个参数,则参数指定应该取回的行数,偏移量默认为0,即从第一行起。
对于预编译SQL语句,可以使用占位符:
/*取回第一行数据*/
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还支持LIMIT row_count OFFSET offset 的语法。
如果子查询中有LIMIT,而外部的查询同样有LIMIT,此时最外层查询的LIMIT优先。例如,以下语句返回的行应该是2条,而不是1条:
(SELECT ... LIMIT 1) LIMIT 2;
2.16
PROCEDURE子句命名了一个对结果集进行处理的存储过程。Section 8.4.2.4, “Using PROCEDURE ANALYSE” 这一节,描述了ANALYSE关键字的使用。一个存储过程,可用于获取有助于减少表大小的最佳列数据类型的建议。(点进去才发现从MySQL 5.7.18开始,PROCEDURE ANALYZE()已被弃用,并在MySQL 8.0中被删除。)
2.17
SELECT...INTO可以让查询结果写入到文件或者保存到变量中,后续的文章会讲这个。
2.18
如果使用在一个使用了页级锁或者行级锁的存储引擎中使用FOR UPDATE,被某个查询所检查的行将会处于“写锁定”中,直到当前事务结束。使用LOCK IN SHARE MODE设置共享锁,允许其他事务读取已检查的行,但不允许更新或删除它们。See Section 14.7.2.4, “Locking Reads”.
此外,你不能在下面的语句中将FOR UPDATE作为SELECT查询的一部分:
CREATE TABLE new_table SELECT ... FROM old_table ....
如果尝试这么做,该语句会被拒绝,并报错——Can't update table 'old_table' while 'new_table' is being created。在MySQL 5.5以及更早的版本中有所不同。(This is a change in behavior from MySQL 5.5 and earlier, which permitted CREATE TABLE ... SELECT statements to make changes in tables other than the table being created.)
三、SELECT关键字的修饰符
紧跟SELECT关键字,你可以使用一些列修饰符,来影响语句的操作。
HIGH_PRIORITY,STRAIGHT_JOIN和以SQL_开头的修饰符是标准SQL的MySQL扩展。
3.1
ALL和DISTINCT修饰符指定是否对结果集中的行(应该不是某个列)去重。
ALL是默认修饰符,即满足要求的所有行都要被取回来。
DISTINCT删除重复的行。
3.2
HIGH_PRIORITY修饰符会让SELECT语句比更改表(这里英文用得是update,不晓得是更新还是更改)的语句有更高的优先级。
这个修饰符只应该在非常快且能被立即执行的查询当中使用。
在表被锁定以进行读取时发出的SELECT HIGH_PRIORITY查询也会运行,即使有一个更新语句正在等待表被释放。这仅影响仅使用表级锁定的存储引擎(例如MyISAM,MEMORY和MERGE)。
HIGH_PRIORITY不能与属于UNION的SELECT语句一起使用。
3.3
STRAIGHT_JOIN强制优化器按照FROM子句中列出的顺序连接表。如果优化程序以非最佳顺序连接表,则可以使用此方法加速查询.STRAIGHT_JOIN也可以在table_references列表中使用。JOIN语法中会讲到。
STRAIGHT_JOIN不适用于被优化器视为const或system的任何表。这种表只产生一行数据,在查询执行的优化阶段读取,并且在查询执行进行之前用适当的列值替换对其列的引用。这些表将首先出现在EXPLAIN显示的查询计划中。See Section 8.8.1, “Optimizing Queries with EXPLAIN”.
This exception may not apply to const or system tables that are used on the NULL-complemented side of an outer join (that is, the right-side table of a LEFT JOIN or the left-side table of a RIGHT JOIN.
3.4
SQL_BIG_RESULT或SQL_SMALL_RESULT可以与GROUP BY或DISTINCT一起使用,分别告诉优化器结果集有很多行或者很小。
对于SQL_BIG_RESULT,MySQL直接使用基于磁盘的临时表(如果已创建),并且更偏向使用在GROUP BY中元素的key的临时表来进行排序。
对于SQL_SMALL_RESULT,MySQL使用内存中的临时表来存储生成的表而不是使用排序。通常不需要这样做。
3.5
SQL_BUFFER_RESULT强制将结果放入临时表中.
这有助于MySQL尽早释放表锁,在需要很长时间将结果集发送到客户端的情况下,这样也更好。
此修饰符只能用于顶级SELECT语句,不能用于子查询或UNION之后。
3.6
SQL_CALC_FOUND_ROWS告诉MySQL计算结果集中将有多少行,忽略任何LIMIT子句。
然后可以使用SELECT FOUND_ROWS()检索行数。See Section 12.15, “Information Functions”.
这个参数就是为了方便统计在不使用LIMIT时的结果集。
3.7
SQL_CACHE和SQL_NO_CACHE修饰符会影响查询缓存中查询结果的缓存。(see Section 8.10.3, “The MySQL Query Cache”)
SQL_CACHE告诉MySQL将结果存储在查询缓存中(如果它是可缓存的,并且query_cache_type系统变量的值是2或DEMAND)。
使用SQL_NO_CACHE,服务器不使用查询缓存。它既不检查查询缓存,也不检查结果是否已缓存,也不缓存查询结果。
这两个修饰符是互斥的,如果同时指定它们则会发生错误。
此外,子查询(包括FROM子句中的子查询)和第一个SELECT以外的UNION中的SELECT语句不允许使用这些修饰符。
对于视图,如果SQL_NO_CACHE出现在查询中的任何SELECT中,则适用
For a cacheable query, SQL_CACHE applies if it appears in the first SELECT of a view referred to by the query.
从MySQL 5.7.20开始,不推荐使用查询缓存,并在MySQL 8.0中删除。弃用包括SQL_CACHE和SQL_NO_CACHE。
最后还有一个关于对分表查询时锁定情况因存储引擎不同而不同的段落。
With SQL_NO_CACHE
, the server does not use the query cache. It neither checks the query cache to see whether the result is already cached, nor does it cache the query result.
MySQL SELECT语法(一)SELECT语法详解的更多相关文章
- Solr系列五:solr搜索详解(solr搜索流程介绍、查询语法及解析器详解)
一.solr搜索流程介绍 1. 前面我们已经学习过Lucene搜索的流程,让我们再来回顾一下 流程说明: 首先获取用户输入的查询串,使用查询解析器QueryParser解析查询串生成查询对象Query ...
- (转载) Linux IO模式及 select、poll、epoll详解
注:本文是对众多博客的学习和总结,可能存在理解错误.请带着怀疑的眼光,同时如果有错误希望能指出. 同步IO和异步IO,阻塞IO和非阻塞IO分别是什么,到底有什么区别?不同的人在不同的上下文下给出的答案 ...
- (转)Linux IO模式及 select、poll、epoll详解
本文为转载,并作了部门调整.修改. [原文出处:https://segmentfault.com/a/1190000003063859] 同步IO和异步IO,阻塞IO和非阻塞IO分别是什么,到底有什么 ...
- 网络通信 --> IO多路复用之select、poll、epoll详解
IO多路复用之select.poll.epoll详解 目前支持I/O多路复用的系统调用有 select,pselect,poll,epoll,I/O多路复用就是通过一种机制,一个进程可以监视 ...
- I/O模型之二:Linux IO模式及 select、poll、epoll详解
目录: <I/O模型之一:Unix的五种I/O模型> <I/O模型之二:Linux IO模式及 select.poll.epoll详解> <I/O模型之三:两种高性能 I ...
- Linux IO模式及 select、poll、epoll详解(转)
同步IO和异步IO,阻塞IO和非阻塞IO分别是什么,到底有什么区别?不同的人在不同的上下文下给出的答案是不同的.所以先限定一下本文的上下文. 本文讨论的背景是Linux环境下的network IO. ...
- 《手把手教你》系列技巧篇(三十二)-java+ selenium自动化测试-select 下拉框(详解教程)
1.简介 在实际自动化测试过程中,我们也避免不了会遇到下拉选择的测试,因此宏哥在这里直接分享和介绍一下,希望小伙伴或者童鞋们在以后工作中遇到可以有所帮助. 2.select 下拉框 2.1Select ...
- 【转】MySQL用户管理及SQL语句详解
[转]MySQL用户管理及SQL语句详解 1.1 MySQL用户管理 1.1.1 用户的定义 用户名+主机域 mysql> select user,host,password from mysq ...
- (转)总结之:CentOS 6.5 MySQL数据库的基础以及深入详解
总结之:CentOS 6.5 MySQL数据库的基础以及深入详解 原文:http://tanxw.blog.51cto.com/4309543/1395539 前言 早期MySQL AB公司在2009 ...
- MYSQL之数据库初识、安装详解、sql语句基本操作
目录 MYSQL之数据库初识及安装详解 1.什么是数据库? 1.什么是数据?(data) 2.什么是数据库?(databases,简称DB) 2.为什要用数据库? 3.什么是数据库管理系统?(Data ...
随机推荐
- instr和like的使用区别
1.instr函数 instr函数是一个字符串处理函数,它在Oracle/PLSQL中是返回子字符串在源字符串中的位置,如果在源串中没有找到子串,则返回0. instr函数定义如下: /* * 返回子 ...
- SQL连接查询基础知识点
什么是连接 连接(join)查询是基于多个表中的关联字段将数据行拼接到一起,可以同时返回多个表中的数据. 下面以两个表为例子,举例说明一下不同的连接. SELECT * FROM products i ...
- CLR 虚方法调用和接口方法调用
不知接口方法和虚方法分发有什么区别?似乎在CIL中都是callvirt指令. 对,MSIL里都是callvirt,但JIT的时候得到了不同的处理:对虚方法的分发是编译成这样: mov ecx, es ...
- .NET Standard
A formal specification of the APIs that are common across .NET implementations What is .NET Standard ...
- poj1734
Sightseeing trip Time Limit: 1000MS Memory Limit: 65536K Total Submissions: 9078 Accepted: 3380 ...
- 图像质量评价-NQM和WPSNR
王保全. 基于混合专家模型的快速图像超分辨率方法研究与实现[D]. 2015. PSNR 和SSIM 在有时候并不能很确切的表示图像质量 标准,该论文中根据一定量的人为的感知评分作为参考,用斯皮尔曼等 ...
- [go]日志库小例子
输出日志 //输出日志到console msg := fmt.Sprintf(format, args...) //format里的坑 args解出的数据相匹配 fmt.Fprintf(os.Stdo ...
- SQL-W3School-高级:SQL 约束(Contraints)
ylbtech-SQL-W3School-高级:SQL 约束(Contraints) 1.返回顶部 1. SQL 约束 约束用于限制加入表的数据的类型. 可以在创建表时规定约束(通过 CREATE T ...
- OpenNESS,开源的边缘网络服务平台
目录 文章目录 目录 参考文章 OpenNESS 的电梯间演讲 OpenNESS 与 ETSI MEC Edge Controller Software 的功能清单 Edge Platform Sof ...
- Android之FrameWork
1 Activity的生命周期和启动模式 1.1 Activity的生命周期全面分析 用户正常使用情况下的生命周期 & 由于Activity被系统回收或者设备配置改变导致Activity被销毁 ...