5 SQL 复杂查询
5 复杂查询
5-1 视图
究竟视图是什么呢?如果用一句话概述的话,就是“从SQL的角度来看视图就是一张表”。实际上,在SQL语句中并不需要区分哪些是表,哪些是视图。
那么视图和表到底右什么不同呢?区别只有一个,那就是“是否保存了实际的数据”。
通常,我们在创建表时,会通过INSERT语句将数据保存到数据库之中。而数据库中的数据实际上会被保存到计算机的存储设备(通常是硬盘)中。因此,我们通过SELECT语句查询数据时,实际上就是从存储设备(硬盘)中读取数据,进行各种计算之后,再将结果返回给用户这样一个过程。
但是使用视图时并不会将数据保存到存储设备之中,而且也不会将数据保存到其他任何地方。实际上视图保存的是SELECT语句。我们从视图中读取数据时,视图会在内部执行该SELECT语句并创建出一张临时表。
视图的优点大体有两点:第一点是由于视图无需保存数据,因此可以节省存储设备的容量。第二个优点就是可以将频繁使用的select语句保存成视图,这样就不用每次都重新书写了。而且还可以大大提高效率。而且视图中的数据会随着原表的变化自动更新。
|
法则5-1 |
|
表中存储的是实际数据,而视图中保存的是从表中取出数据所使用的SELECT语句。 |
|
法则5-2 |
|
应该将经常使用的SELECT语句做成视图。 |
|
创建视图的方法 |
|
/* CREATE VIEW 视图名称(<视图列名1>, <视图列名2>, ......) AS <SELECT语句> */ DELETE FROM shohin; SELECT * FROM shohin; INSERT INTO shohin VALUES ('0001', 'T恤衫', '衣服', 1000, 500, '2009-09-20'); INSERT INTO shohin VALUES ('0002', '打孔器', '办公用品', 500, 300, '2009-09-11'); INSERT INTO shohin VALUES ('0003', '运动T恤', '衣服', 4000, 2800, NULL); INSERT INTO shohin VALUES ('0004', '菜刀', '厨房用具', 3000, 2800, '2009-09-20'); INSERT INTO shohin VALUES ('0005', '高压锅', '厨房用具', 6800, 5000, '2009-01-15'); INSERT INTO shohin VALUES ('0006', '叉子', '厨房用具', 500, NULL, '2009-09-20'); INSERT INTO shohin VALUES ('0007', '擦菜饭', '厨房用具', 880, 790, '2008-04-28'); INSERT INTO shohin VALUES ('0008', '圆珠笔', '办公用品', 100, NULL, '2009-11-11'); CREATE VIEW shohinSum (shohin_bunrui, cnt_shohin) AS SELECT shohin_bunrui, COUNT(*) FROM shohin GROUP BY shohin_bunrui; SELECT * FROM shohinSum; |
在FROM子句中使用视图的查询,通常有如下两个步骤:
首先执行定义视图的SELECT语句,根据得到的结果,再执行在FROM子句中使用视图的SELECT语句。
也就是说,使用视图的查询通常需要执行2条以上的SELECT语句。
多重视图。
|
使用视图的查询 |
|
CREATE VIEW shohinSumJim (shohin_bunrui, cnt_shohin) AS SELECT shohin_bunrui, cnt_shohin FROM shohinSum WHERE shohin_bunrui = '办公用品'; |
虽然语法上没有错误,但是我们还是应该尽量避免在视图的基础上创建视图。这是因为对于多数DBMS来说,多重视图会降低SQL的性能。
|
法则5-3 |
|
应该避免在视图的基础上创建视图 |
为什么不能使用ORDER BY子句呢?这是因为视图和表一样,数据行都是没有顺序的。实际上,有些DBMS在定义视图的语句中是可以使用ORDER BY子句的,但是这并不是通用的语法。因此,在定义视图时请不要使用ORDER BY。
|
法则5-4 |
|
定义视图时不要使用ORDER BY子句。 |
|
法则5-5 |
|
视图和表需要同时进行更新,因此通过聚合得到的视图无法进行更新。 |
|
删除视图 |
|
-- DROP VIEW 视图名称(<视图列名1>, <视图列名2>, ......); DROP VIEW shohinSum; |
5-2 子查询
我们先来复习一下视图的概念,视图并不是用来保存数据的,而是通过保存读取数据的SELECT语句的方法来为用户提供便利的工具。反之,子查询就是将用来定义视图的SELECT语句直接用于FROM子句当中。
|
子查询和视图 |
|
CREATE VIEW shohinSum (shohin_bunrui, cnt_shohin) AS SELECT shohin_bunrui, COUNT(*) FROM shohin GROUP BY shohin_bunrui; -- 下面代码也能实现此功能 这里的内层 SELECT子句为 FROM子句中的select子句 SELECT shohin_bunrui, cnt_shohin FROM (SELECT shohin_bunrui, COUNT(*) AS cnt_shohin FROM shohin GROUP BY shohin_bunrui) AS shohinSum; /* 首先执行from子句中的select语句(子查询) SELECT shohin_bunrui, COUNT(*) AS cnt_shohin FROM shohin GROUP BY shohin_bunrui; 根据上面的结果执行外层的select语句 SELECT shohin_bunrui, cnt_shohin FROM shohinSum; */ SELECT shohin_bunrui, cnt_shohin FROM shohinSum; SELECT shohin_bunrui, cnt_shohin FROM (SELECT * FROM (SELECT shohin_bunrui, COUNT(*) AS cnt_shohin FROM shohin GROUP BY shohin_bunrui) AS shohinSum WHERE cnt_shohin = 4) AS shohinSum2; |
|
法则5-6 |
|
子查询作为内层查询会首先执行。 |
子查询的名称:原则上子查询必须设定名称,因此请大家尽量从处理内容的角度出发为子查询设定恰当的名称。为子查询设定名称时需要使用AS关键字,该关键字有时也可以省略。
标量就是单一的意思,在数据库之外的领域也经常使用。
标量子查询则有一个特殊的限制,那就是必须而且只能返回1行1列的结果。
|
标量子查询(scalar subquery) |
|
-- 在where子句中使用标量子查询 -- 在where子句中不能使用聚合函数 -- 虽然这样的select语句看上去能够满足我们的要求,但是由于在where子句中不能使用聚合函数,因此这样的select语句是错误的。 SELECT shohin_id, shohin_mei, hanbai_tanka FROM shohin WHERE hanbai_tanka > AVG(hanbai_tanka); -- 可以使用下面的代码实现 -- 计算平均销售单价的标量子查询 SELECT AVG(hanbai_tanka) FROM shohin; SELECT shohin_id, shohin_mei, hanbai_tanka FROM shohin WHERE hanbai_tanka > (SELECT AVG(hanbai_tanka) FROM shohin); -- 在SELECT子句中使用标量子查询 SELECT shohin_id, shohin_mei, hanbai_tanka, (SELECT AVG(hanbai_tanka) FROM shohin) AS avg_tanka FROM shohin; SELECT shohin_bunrui, AVG(hanbai_tanka) FROM shohin GROUP BY shohin_bunrui; -- 在HAVING子句中使用标量子查询 SELECT shohin_bunrui, AVG(hanbai_tanka) FROM shohin GROUP BY shohin_bunrui HAVING AVG(hanbai_tanka) > (SELECT AVG(hanbai_tanka) FROM shohin); |
|
法则5-7 |
|
标量子查询就是返回单一值的子查询 |
标量子查询的书写位置并不仅仅局限于WHERE子句中,通常任何可以使用单一值的位置都可以使用。也就是说,能够使用常数或者列名的地方,无论是SELECT子句,GROUP BY子句,HAVING子句,还是ORDER BY子句,几乎所有的地方都可以使用。
特别需要注意的是该子查询绝对不能返回多行结果。也就是说如果子查询返回了多行结果,那么它就不再是标量子查询,而仅仅是一个普通的子查询了。
5-3 关联子查询
在WHERE子句中使用子查询时,该子查询的结果必须是单一的。
|
普通的子查询和关联子查询的区别 |
|
-- 普通的子查询和关联子查询的区别 SELECT AVG(hanbai_tanka) FROM shohin GROUP BY shohin_bunrui; -- 发生错误的子查询 SELECT shohin_id, shohin_mei, hanbai_tanka FROM shohin WHERE hanbai_tanka > (SELECT AVG(hanbai_tanka) FROM shohin GROUP BY shohin_bunrui); -- 正确的关联子查询书写方法 SELECT shohin_id, shohin_mei, hanbai_tanka FROM shohin AS S1 WHERE hanbai_tanka > (SELECT AVG(hanbai_tanka) FROM shohin AS S2 WHERE S1.shohin_bunrui = S2.shohin_bunrui GROUP BY shohin_bunrui); -- 错误的关联子查询书写方法:将关联条件移到子查询之外 该书写方法究竟违法了什么规则呢?那就是关联名称的作用域。也就是说关联名称存在一个有效作用域的限制。 SELECT shohin_bunrui, shohin_mei, hanbai_tanka FROM shohin AS S1 WHERE S1.shohin_bunrui = S2.shohin_bunrui AND hanbai_tanka > (SELECT AVG(hanbai_tanka) FROM shohin AS S2 GROUP BY shohin_bunrui); -- 正确的关联子查询书写方法 SELECT shohin_bunrui, shohin_mei, hanbai_tanka FROM shohin AS S1 WHERE hanbai_tanka > (SELECT AVG(hanbai_tanka) FROM shohin AS S2 WHERE S1.shohin_bunrui = S2.shohin_bunrui GROUP BY shohin_bunrui); |
这里起到关键作用的就是在子查询中添加的WHERE子句的条件。
请大家一定不要忘记关联名称具有一定的有效作用域。如前所述,SQL是按照先内层子查询后外层查询的顺序来执行的。这样,子查询执行结束时会留下执行结果,作为抽出源的S2表其实已经不存在了。因此,在执行外层查询时,由于S2表已经不存在了,就会返回“不存在使用该名称的表”这样的错误。
|
法则5-8 |
|
在细分的组内进行比较时,需要使用关联子查询。 |
5 SQL 复杂查询的更多相关文章
- Linq to SQL 语法查询(链接查询,子查询 & in操作 & join,分组统计等)
Linq to SQL 语法查询(链接查询,子查询 & in操作 & join,分组统计等) 子查询 描述:查询订单数超过5的顾客信息 查询句法: var 子查询 = from c i ...
- SQL联合查询:子表任一记录与主表联合查询
今天有网友群里提了这样一个关于SQL联合查询的需求: 一.有热心网友的方案: 二.我的方案: select * from ( select a.*,(select top 1 Id from B as ...
- SQL 提高查询效率
1.关于SQL查询效率,100w数据,查询只要1秒,与您分享: 机器情况p4: 2.4内存: 1 Gos: windows 2003数据库: ms sql server 2000目的: 查询性能测试, ...
- sql语句查询
1. sql语句查询某位数字或者某几位数字开头的数据,字段类型为数字类: %’: 2. sql搜索以4开头和含有李字的数据: select * from wlzbpre_user where real ...
- SQL联合查询(内联、左联、右联、全联)的语法(转)
最近在做一个比较复杂的业务,涉及的表较多,于是在网上找了一些sql联合查询的例子进行研究使用. 概述: 联合查询效率较高,举例子来说明联合查询:内联inner join .左联left outer j ...
- phpcmsv9自定义sql语句查询模型实现
在phpcmsv9中,自定义sql语句查询可不太好实现,传入sql语句查询很容易被内部转入生成一系列莫名其妙的sql语句,比如最佳前缀等等,直接造成sql语句查询错误,在此也提供两种解决办法,1修改底 ...
- [转]一个用户SQL慢查询分析,原因及优化
来源:http://blog.rds.aliyun.com/2014/05/23/%E4%B8%80%E4%B8%AA%E7%94%A8%E6%88%B7sql%E6%85%A2%E6%9F%A5%E ...
- 怎样用SQL语句查询一个数据库中的所有表?
怎样用SQL语句查询一个数据库中的所有表? --读取库中的所有表名 select name from sysobjects where xtype='u'--读取指定表的所有列名select nam ...
- SQL组合查询的存储过程写法
最进一个项目 里面有个查询的功能,它是进行组合查询的, 而且用的是存储过程写.写这样的存储过程,需要注意单引号的使用,请看本人下面的例子,假如你以后写的话 记得注意写就行: create proc s ...
- 通过Spark SQL关联查询两个HDFS上的文件操作
order_created.txt 订单编号 订单创建时间 -- :: -- :: -- :: -- :: -- :: order_picked.txt 订单编号 订单提取时间 -- :: ...
随机推荐
- bzoj 3992: [SDOI2015]序列统计【原根+生成函数+NTT+快速幂】
还是没有理解透原根--题目提示其实挺明显的,M是质数,然后1<=x<=M-1 这种计数就容易想到生成函数,但是生成函数是加法,而这里是乘法,所以要想办法变成加法 首先因为0和任何数乘都是0 ...
- 严格次小生成树(lca + 倍增)
题目描述 小C最近学了很多最小生成树的算法,Prim算法.Kurskal算法.消圈算法等等.正当小C洋洋得意之时,小P又来泼小C冷水了.小P说,让小C求出一个无向图的次小生成树,而且这个次小生成树还得 ...
- HDU6438(贪心技巧)
第一眼喜闻乐见的股票问题dp可以暴力,然鹅时间不允许. 于是考虑怎么贪. 这篇题解说得很生动了. 因为每支股票都有买入的潜力所以肯定都加在优先队列里. 然后考虑的是哪些需要加入两次.这是我第二次见到类 ...
- Music in Car CodeForces - 746F
Music in Car CodeForces - 746F 题意很难懂啊... 题意:http://blog.csdn.net/a838502647/article/details/74831793 ...
- oracle 10g standby 设置
##########sample alter system set log_archive_dest_1 = 'LOCATION=USE_DB_RECOVERY_FILE_DEST' scope=bo ...
- redirect与forward的区别
文件名称:forward.jsp <html> <head><title> 跳转 </title> </head> <body> ...
- 非常强大的前端插件:emmet
安装 Emmet 也有快速生成文件头的功能啊,而且更强大啊输入下边加粗的缩写,然后Tab,就OK了啊http://docs.emmet.io/cheat-sheet/ html:4t <!DOC ...
- P3717 [AHOI2017初中组]cover
题目背景 以下为不影响题意的简化版题目. 题目描述 一个n*n的网格图上有m个探测器,每个探测器有个探测半径r,问这n*n个点中有多少个点能被探测到. 输入输出格式 输入格式: 第一行3个整数n,m, ...
- img 标签访问图片返回403forbidden
做百度编辑器时,从秀米复制过来的文档,图片不无法加载,返回403的错 解决办法 解决这个问题只需要在头部添加一个meta <meta name="referrer" cont ...
- 关于IE 对 $.get 缓存的记录
最近在IE9中碰到一个问题是, 当我对某个角色进行修改的时候,再点击查询还是修改之前的内容,但是实际数据库已经修改成功,纠结了好一会儿之后,才发现是 $.get请求的问题. 因为 IE对get请求, ...