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 ...
随机推荐
- JEET W1S运动蓝牙耳机简评
对于我这种喜欢运动的人来说,很早之前就一直想买个运动蓝牙耳机了.这次正好有此机会可以评测来自JEET的W1S运动蓝牙耳机,真的是非常的幸运! 终于,在期盼中,我的来自深圳的快递隔了四天终于到了!JEE ...
- Linux中su、sudo、sudo -i的用法和区别
sudo :暂时切换到超级用户模式以执行超级用户权限,提示输入密码时该密码为当前用户的密码,而不是超级账户的密码.缺点是每次执行超级用户权限都要在命令前加上 sudo ,优点是在当前终端再使用 sud ...
- XCTF-shrine
shrine 直接看题 进来给了个python代码 import flask import os app = flask.Flask(__name__) app.config['FLAG'] = os ...
- OpenStack+kvm虚拟机xml格式解析
配置说明 首先介绍一下配置结构: xml配置遵循<keyword> xxxxxx </keyword>的格式,即一个配置段以<keyword>开头,以</ke ...
- Day007 数组的声明与创建
数组 数组的定义 数组是相同类型数据的有序集合. 数组描述的是相同类型的若干个数据,按照一定的先后次序排列组合而成. 其中,每一个数据称作一个数组元素,每个数组元素可以通过一个下标来访问它们. 数组声 ...
- RxJava线程控制
RxJava中的线程转换主要通过下面两个方法: 1.subscribeOn 2.observeOn 一.subscribeOn 1.调用一次subscribeOn时: Observable obser ...
- c#RSA 私钥加签公钥解签
/// RSA签名 /// </summary> /// <param name="data">待签名数据</param> /// <pa ...
- dynamic_cast和typeid
1. C++有三个支持RTTI的元素. 如果可能的话,dynamic_cast运算符将使用一个指向基类的指针来生成一个指向派生类的指针,否则,该运算符返回0--空指针. typeid运算符返回一个对t ...
- 【敏杰开发】Beta阶段项目展示
[敏杰开发]Beta阶段项目展示 项目相关地址汇总 线上地址:http://roadmap.imcoming.top 前端仓库:https://github.com/MinJieDev/Roadmap ...
- 墙裂推荐一波mysql学习资源
在日常工作与学习中,无论是开发.运维.测试,还是架构师,数据库是一门必不可少的"必修课", 也是必备的涨薪神器.在互联网公司中,开源数据库用得比较多的当属 MySQL 了. 但my ...