SQL进阶总结(二)
2、第二个特性----以集合为单位进行操作
在我们以往面向过程语言不同,SQL是一门面向集合的一门语言。由于习惯了面向过程的思考方式,导致我们在使用SQL时往往也陷入之前的思维定式。
我们现在分别创建customers表和orders表
customers orders
我们最直观看到数据库的数据组织方式是通过 视图查询出来,就像上面两张图我们所看到的一样。
而数据库存储数据其实是如下两张图
customers和orders的集合
想了下怎么讲解这个以集合为单位进行操作最后还得通过案例进行说明,而最能体现这个特性就在于对 Having 的使用。
例一:求众数
以面向过程的思路分析这道题是如下步骤:
1)创建一个MAP<item,num>集合,item是数字,num是出现的次数。
2)对输入的数组集合作遍历,并判断MAP中是否存在该数字,若存在则将num+1,若不存在则将数字放入MAP中。
3)对MAP中num属性提取出最大值。
4)通过最大num值在MAP中找到相应的数字。
而在面向集合中解题思路应该是这样的:
1)对数组列表中每一个数字进行分组
2)计算每一组数字的个数 并 要大于任何一组数字的个数 ,该数字即为该数组的众数。
--求众数SQL语句(1):使用谓词
SELECT income,COUNT(*) AS cnt FROM Graduates GROUP BY income HAVING COUNT(*) >= ALL (SELECT COUNT(*) FROM Graduates GROUP BY income) --求众数SQL语句(2):使用极值函数
SELECT income,COUNT(*) AS cnt FROM Graduates GROUP BY income Having COUNT(*) >= ( SELECT MAX(cnt) FROM (SELECT COUNT(*) AS cnt FROM Graduates GROUP BY income) TMP);
分组集合操作
例二:求中位数
面向过程解析:
1)对集合进行大小排序。
2)如果是奇数则取集合中间一个数字为中位数,如果是偶数则取中间两个数字的平均值为中位数。
面向集合解析:
1)将集合按大小分为上半部分和下半部分两个子集
2)让两个子集同时拥有的元素取平均值就为中位数
SELECT AVG(DISTINCT income)
FROM
(SELECT
a.income
FROM
Graduates a,Graduates b
GROUP BY a.income
HAVING
SUM(CASE WHEN a.income >= b.income THEN 1 ELSE 0 END) >= COUNT(*)/2
AND SUM(CASE WHEN a.income <= b.income THEN 1 ELSE 0 END) >= COUNT(*)/2
)TMP
例三:查询所有学生都提交了报告的学院
面向过程解析:
1)对数组集合进行循环遍历筛选出提交日期为空的学院
2)对第一步产生的结果再原数组集合作差集,筛选出所有提交报告的学院
面向集合解析:
1)对集合按照学院分组,并统计每个学院已提交报告的数量
2)对第一步产生结果与原集合按学院分组后的数量进行比对,若数量一致则为已提交所有报告的学院
SELECT COUNT(*) FROM Students GROUP BY COUNT(*) = COUNT(sbmt_date)
例四:关系除法运算
Items ShopItems
1.查询包含在Items所有商品的商店
面向过程解析:
1)在 shopitems 表中按照店铺作数组拆分
2)对拆分出来的数组中所售商品按照Items进行遍历比对,若检测其中任意一个Items商品不在该数组中则将其筛选出。
面向集合解析:
1) 将shopitems按照店铺分组 并 对 shopitems 与 items 按照 item 做关联
2) 统计关联后的分组结果数量是否和Items表中商品数量是否一致
/*查询店铺中包含表Items中所有商品的店铺*/
SELECT
shop
FROM
ShopItems a,Items b
WHERE a.item = b.item
GROUP BY shop
HAVING COUNT(*) = (SELECT COUNT(*) FROM Items)
2.精确关系除法
第一个问题按照上述逻辑会筛选出东京和仙台,而仙台还包含有“窗帘”这一项在Items是不存在的,这样的查询称之为 带余除法
现在我们要从shopitems筛选出与items完全重合店铺信息,就是只需要筛选出东京。这个问题称之为 精确关系除法。
1) 将shopitems按照店铺分组 并 对 shopitems 与 items 按照 item 做外关联,确保shopitems中的元素不会缺失
2)让匹配到的 items 中的元素与 Items数量作比较是否一致
3)比较店铺中所有商品与匹配到的商品数量是否一致
通过(2)能够确保 在Items中存在的商品都存在于店铺中
通过(3)能够确保 店铺中的商品数量是与匹配到的商品数量是一致的
在有了(2)的前提下,若满足(3)的条件,则说明店铺中商品是和商品表里的商品是一一对应的。
/*精确关系除法*/
SELECT
shop
FROM
ShopItems a LEFT JOIN Items b
ON a.item = b.item
GROUP BY shop
HAVING COUNT(b.item) = (SELECT COUNT(*) FROM Items)
AND COUNT(a.item) = COUNT(b.item)
3.这里我们再解析下什么是关系除法
首先这里我们给出它的数学定义:
然后我们再按照上述定义来解析这两道题
1)shopitems表中存在两个属性,shop属性和Item属性;items表中存在item一个属性;他们的共同属性为item
2)Items在shopitems上的投影为
2)shopitems表分量shop属性的象集为:
象集1 象集2 象集3
3)那么我们能看3个象集中包含关系Items在shopitems上的投影的是 象集1和象集2
最后我们再通过下面两张图就更清楚,带余除法和精确除法的关系了
带余除法 精确除法
这就是关系除法的原理,那为什么这样的运算称之为除法运算呢?
答:因为这样会产生一个结果(商),通过再与我们的除数进行笛卡尔积运算能够得到被除数的子集或者被除数本身。由于笛卡尔积运算我们称之为乘法运算,那么作为它的逆向运算就为除法运算了。
例五:行转列 制作交叉表
那么本题还是应该使用集合的思想来解题,我们将原数据按下图整理
我们按人名对集合进行分为5组后,Group by name 的 name的值 就能作为我们的侧边栏,而表头则需要我们自己作定义,根据每个分组里面的值进行判断。
举例:赤井这个分组我们根据已知表头中三个课程进行判断,如果相同则标记为‘O’;不同则标记为‘X’。
/*课程记录一览表*/
SELECT
a.name,
MAX(CASE WHEN course = 'SQL入门' THEN '○' ELSE '×' END) AS 'SQL入门',
MAX(CASE WHEN course = 'UNIX基础' THEN '○' ELSE '×' END) AS 'UNIX基础',
MAX(CASE WHEN course = 'Java中级' THEN '○' ELSE '×' END) AS 'Java中级'
FROM
Courses a
GROUP BY a.name
例六:移动累计值
Accounts
1)求截止到某个处理日期的处理金额的累计值,实际上就是求截止到那个时间点的账户余额
本题还是得用集合的思想解决,但是现在日期都不同,那么现在以什么作为分组呢?
答案是我们需要作一次自关联,让其产生一个每个日期小于等于它本身的日期集合,然后对这个集合统一作累计计算。
/* 求累计值 */
SELECT
prc_date,
prc_amt,
(SELECT SUM(prc_amt) FROM Accounts b WHERE a.`prc_date` >= b.prc_date) AS onhand_amt
FROM
Accounts a
2)我们考虑一下如何以3次处理为单位求累计值,即移动累计值。所谓移动,指的是将累计的数据行数固定(本例中为3行),一行一行地偏移,如下表所示。
还是根据刚才所讲按每个日期和每个比他本身小的日期作分组,不过这次还要加上在区间范围不超过3的条件
/*求移动累计值*/
SELECT a.`prc_date`,SUM(b.`prc_amt`)
FROM Accounts a,Accounts b
WHERE a.`prc_date` >= b.`prc_date` AND
(SELECT COUNT(*) FROM Accounts c WHERE c.`prc_date` BETWEEN b.`prc_date` AND a.`prc_date`)<=3
GROUP BY a.`prc_date`
对于区间不满三行的数据则不输出
/*不满三行不作输出*/
SELECT a.`prc_date`,SUM(b.`prc_amt`)
FROM Accounts a,Accounts b
WHERE a.`prc_date` >= b.`prc_date` AND
(SELECT COUNT(*) FROM Accounts c WHERE c.`prc_date` BETWEEN b.`prc_date` AND a.`prc_date`)<=3
GROUP BY a.`prc_date`
HAVING COUNT(*) = 3
例七:查询重叠的时间区间
Reservations
本题作自关联,为每一个时间段预先制造一个分组集合,在集合内先完成条件筛选。
/**查询住宿重叠时间**/
SELECT
reserver,
astart,
aend
FROM
(
SELECT
a.reserver,a.start_date AS astart,a.end_date AS aend,b.start_date AS bstart,b.end_date AS bend
FROM Reservations a,Reservations b WHERE a.reserver <> b.reserver
)tmp
WHERE bstart BETWEEN astart AND aend
OR bend BETWEEN astart AND aend
OR bstart BETWEEN astart AND aend AND bend BETWEEN astart AND aend
例8:查询两个集合是否相等
tbl_A tbl_B
如何比较这两个集合元素是否是相等的呢
1)那我们可以使用 A+B=A=B 的条件来判断这样的场景
/*判断集合是否相等*/
SELECT COUNT(*) FROM (
SELECT * FROM tlb_A
UNION
SELECT * FROM tlb_B
)TMP
2)第一种解法就要先确定A和B的行数,那现在想一想能不能直接对A、B进行比较呢?
那可以利用两个集合的并集和差集来判定其相等性。如果用SQL语言描述,那就是“如果A UNION B = A INTERSECT B,则集合A和集合B相等”。
(A ∪ B ) = (A ∩ B) ⇔ (A = B)
/*判断集合是否相等*/
SELECT CASE WHEN COUNT(*) = 0 THEN '相等' ELSE '不相等' END AS result
FROM ((SELECT * FROM tbl_A
UNION
SELECT * FROM tbl_B)
EXCEPT
(SELECT * FROM tbl_A
INTERSECT
SELECT * FROM tbl_B)
))TMP;
例9:寻找相等子集
SupParts
问题:找出经营的零件在种类数和种类上都完全相同的供应商组合。
SQL并没有提供任何用于检查集合的包含关系或者相等性的谓词。IN 谓词只能用来检查元素是否属于某个集合,而不能检查集合是否是某个集合的子集。
那我们就先给出答案
/*寻找相等子集*/
SELECT
a.`sup`,b.`sup`
FROM SupParts a,SupParts b
WHERE a.`part` = b.`part` AND a.`sup` < b.`sup`
GROUP BY a.`sup`,b.`sup`
HAVING COUNT(*) = (SELECT COUNT(*) FROM SupParts c WHERE a.`sup` = c.`sup`)
AND COUNT(*) = (SELECT COUNT(*) FROM SupParts d WHERE b.`sup` = d.`sup`)
大家对此是不是比较熟悉
其实这个思路和例四很像,只不过例四是只检查一个集合是否要和另一个集合相等。而本题是需要同时检查两个集合是否都和第三个集合相等。这样保证集合A和集合B关联后记录不会丢失,因为C和D是完整的记录而且都是自己本身。
SQL进阶总结(二)的更多相关文章
- SQL进阶随笔--case用法(一)
SQL进阶一整个是根据我看了pdf版本的整理以及自己的见解整理.后期也方便我自己查看和复习. CASE 表达式 CASE 表达式是从 SQL-92 标准开始被引入的.可能因为它是相对较新的技术,所以尽 ...
- 【SQL进阶】03.执行计划之旅1 - 初探
听到大牛们说执行计划,总是很惶恐,是对知识的缺乏的惶恐,所以必须得学习执行计划,以减少对这一块知识的惶恐,下面是对执行计划的第一讲-理解执行计划. 本系列[T-SQL]主要是针对T-SQL的总结. S ...
- 《SQL基础教程》+ 《SQL进阶教程》 学习笔记
写在前面:本文主要注重 SQL 的理论.主流覆盖的功能范围及其基本语法/用法.至于详细的 SQL 语法/用法,因为每家 DBMS 都有些许不同,我会在以后专门介绍某款DBMS(例如 PostgreSQ ...
- SQL优化之SQL 进阶技巧(下)
上文( SQL优化之SQL 进阶技巧(上) )我们简述了 SQL 的一些进阶技巧,一些朋友觉得不过瘾,我们继续来下篇,再送你 10 个技巧 一. 使用延迟查询优化 limit [offset], [r ...
- SQL优化之SQL 进阶技巧(上)
由于工作需要,最近做了很多 BI 取数的工作,需要用到一些比较高级的 SQL 技巧,总结了一下工作中用到的一些比较骚的进阶技巧,特此记录一下,以方便自己查阅,主要目录如下: SQL 的书写规范 SQL ...
- (一)《SQL进阶教程》学习记录--CASE
背景:最近用到统计之类的复杂Sql比较多,有种"提笔忘字"的感觉,看书练习,举一反三,巩固加强. (一) <SQL进阶教程>学习记录--CASE (二) <SQL ...
- SQL开发技巧(二)
本系列文章旨在收集在开发过程中遇到的一些常用的SQL语句,然后整理归档,本系列文章基于SQLServer系列,且版本为SQLServer2005及以上-- 文章系列目录 SQL开发技巧(一) SQL开 ...
- SQL总结(二)连表查询
---恢复内容开始--- SQL总结(二)连表查询 连接查询包括合并.内连接.外连接和交叉连接,如果涉及多表查询,了解这些连接的特点很重要. 只有真正了解它们之间的区别,才能正确使用. 1.Union ...
- SQL开发技巧(二) 【转】感觉他写的很好
本文转自: http://www.cnblogs.com/marvin/p/DevelopSQLSkill_2.html 本系列文章旨在收集在开发过程中遇到的一些常用的SQL语句,然后整理归档,本系列 ...
- Android高手进阶教程(二十八)之---Android ViewPager控件的使用(基于ViewPager的横向相册)!!!
分类: Android高手进阶 Android基础教程 2012-09-14 18:10 29759人阅读 评论(35) 收藏 举报 android相册layoutobjectclassloade ...
随机推荐
- poj2418map或者字典树
题意: 给你一些串,然后求出每个串出现的概率. 思路: 简单题目,做法也很多,我用字典树做了下,然后又用map做了下,其实这个题目我感觉直接排序一遍之后线性输出应该是最简单最快的( ...
- Qt链接MySQL发布后Drive not loadedDrive not loaded怎么办
缺少动态链接库!把MySQL文件夹下面带dll.lib的全复制进去就行了
- 【python】Leetcode每日一题-旋转链表
[python]Leetcode每日一题-旋转链表 [题目描述] 给你一个链表的头节点 head ,旋转链表,将链表每个节点向右移动 k 个位置. 示例1: 输入:head = [1,2,3,4,5] ...
- Android LayoutInflater.inflate源码解析
一年多以前看过源码,感觉了解比较透彻了,长时间不经大脑思考,靠曾经总结的经验使用inflate方法,突然发现不知道什么时候忘记其中的原理了,上网查了一些资料,还各有不同,反而把我搞糊涂了,还是自己看源 ...
- 推荐几款MySQL相关工具
前言: 随着互联网技术的不断发展, MySQL 相关生态也越来越完善,越来越多的工具涌现出来.一些公司或个人纷纷开源出一些不错的工具,本篇文章主要介绍几款 MySQL 相关实用工具.提醒下,这里并不介 ...
- JWT 基本使用
JWT 基本使用 在上一节中 session 共享功能使用 redis 进行存储,用户量激增时会导致 redis 崩溃,而 JWT 不依赖服务器,能够避免这个问题. 1.传统 session 1.1. ...
- Scrum Meeting 2
Basic Info where:三号教学楼 when:2020/4/25 target: 简要汇报一下已完成任务,下一步计划与遇到的问题 Progress Team Member Position ...
- 80行代码教你写一个Webpack插件并发布到npm
1. 前言 最近在学习 Webpack 相关的原理,以前只知道 Webpack 的配置方法,但并不知道其内部流程,经过一轮的学习,感觉获益良多,为了巩固学习的内容,我决定尝试自己动手写一个插件. 这个 ...
- 如何实现一个简易版的 Spring - 如何实现 AOP(上)
前言 本文是「如何实现一个简易版的 Spring 系列」的第五篇,在之前介绍了 Spring 中的核心技术之一 IoC,从这篇开始我们再来看看 Spring 的另一个重要的技术--AOP.用过 Spr ...
- [ML] 高德软件的路径规划原理
路径规划 Dijkstra s:起点:S:已知到起点最短路径的点:U:未知到起点最短路径的点 Step 1:S中只有起点s,从U中找出路径最短的 Step 2:更新U中的顶点和顶点对应的路径 重复St ...