SQL进阶总结(一)
学而不思则罔,趁着假期好好总结下SQL的编程知识。
掌握SQL,首先有两个知识点要明确,要贯穿在我们整个学习SQL的过程中。
SQL 不同于之前学习的面向过程、面向编程语言,SQL是一门面向集合的编程语言。
面向集合编程语言的特性:
1、三值逻辑判断(TRUE&FALSE&UNKNOWN)
在我们以往我们所接触的编程语言都包含布尔类型,其中只要有TRUE和FALSE两个值,这种逻辑体系被称为二值逻辑。
但是在SQL语言中,除此之外还有第三个值UNKNOWN,这种逻辑体系被称为三值逻辑,三值逻辑的出现是因为在SQL中存在NULL值。
使用要点:
1)NULL值和任何值作比较都是UNKNOWN
1=NULL 、 2>NULL、3<NULL 、4<>NULL、NULL=NULL 结果都为UNKNOWN
2)三值逻辑真值表

其中浅蓝色部分是三值逻辑特有的判断
总结一下就是:在and运算中 FALSE>UNKNOWN>TRUE
在or运算中 TRUE>UNKNOWN>FALSE
3)另外三值逻辑造成的问题就是排中律不存在
例如:在我们正常认知中假设有一群学生,他们年龄肯定是20岁,或者不是20岁,二者必居其一。
那么在我们SQL查询逻辑就应为:
--查询年龄是20岁或者不是20岁的学生
select * from students where age = 20 or age <> 20;
那么显然在我们SQL查询中 如果学生年龄中存在NULL值,上述查询是无法通过将全集查出的。
那么要完全查询出全集则应该为
/*查询全集*/
select * from students where age = 20 or age <> 20 or age is NULL;
4)NOT IN 和 NOT EXISTS是不等价的
首先说明 在SQL查询中 EXISTS总是返回TRUE或FALSE,而 IN 则会返回 TRUE,FALSE还有对于 NULL 值会返回 UNKNOWN。但在过滤器中对 UNKNOWN和FALSE处理方式是相同的,因此在使用EXISTS和IN二者是可以相互替换的。
下面我们将对下面案例进行分析,来探究NOT IN 和 NOT EXISTS的区别

ClassA ClassB
现在我们要查询 “与B班住在东京且年龄不同的A班同学”
那么在 NOT IN 的SQL查询应为
--与B班住在东京的学生年龄不同的A班学生
SELECT * FROM ClassA WHERE age NOT IN (SELECT age FROM ClassB WHERE city = '东京');
通过改写得
--与B班住在东京的学生年龄不同的A班学生
SELECT * FROM ClassA WHERE age NOT IN (22,23,NULL) --SQL处理1:
SELECT * FROM ClassA WHERE NOT (age = 22) or (age = 23) or (age = NULL)
--SQL处理2:
SELECT * FROM ClassA WHERE NOT (TRUE or UNKNOWN)
--通过三值逻辑得
=>SELECT * FROM ClassB WHERE UNKONOWN
则结果集为空
我们再看看NOT EXISTS 如何处理
--与B班住在东京的学生年龄不同的A班学生
SELECT * FROM ClassA a WHERE NOT EXISTS (SELECT age FROM ClassB b WHERE a.age = b.age AND b.city = '东京')
通过改写得
--与B班住在东京的学生年龄不同的A班学生
SELECT * FROM ClassA a WHERE NOT EXISTS (SELECT age FROM ClassB b WHERE a.age = NULL AND b.city = '东京'); --SQL处理1:
SELECT * FROM ClassA a WHERE NOT EXISTS (SELECT age FROM ClassB b WHERE UNKNOWN AND TRUE或者FALSE) --SQL处理2:
--子查询不会返回结果 则父查询返回所有结果集
=> SELECT * FROM ClassA WHERE TRUE
--最后结果集会出现 '拉里' 和 '伯杰' 两条记录
所以我们可以得出结论 当我们筛选的集合中存在 NULL 值时,在使用 NOT IN 查询时总是得到空集,而在使用 NOT EXISTS 总是返回条件匹配的所有结果集。
5)限定谓词和极值函数
SQL当中存在两个限定谓词ALL、ANY,由于ANY与IN是等价的,我们这里就说明一下ALL的用法。
当使用ALL时等价 让每个条件进行AND连接
例如 我们需要计算年龄小于所有输入列表时:
ALL的使用:
age < ALL (11,22,NULL) => (age < 11) and (age < 22) and (age < NULL) => 结果中存在UNKNOWN 那么结果集为空
极值函数的使用:
age < MIN(11,22,NULL) => age < 11 因为极值函数会自动忽略掉 NULL 值
而如果输入列表为一个空集时:
ALL 会返回查询数据表的所有记录,而极值函数则会返回NULL。
整个三值逻辑是基于谓词而来的。
那么谓词是什么?答:谓词是一种特殊的函数,返回值都是真值(true、false或者unknown)
谓词逻辑的出现提供了谓词来判断命题的真假。在关系数据库里,表里每一行数据可以看作是一个命题。

Tbl_A
例如:按照我们之前的理解表里第一行数据是一条记录他有对应的是三个属性值,而按照逻辑谓词的观点为 田中的性别是男,而且年龄是28岁。
谓词的出现是具有划时代意义的,原因就在于为命题分析提供了函数式的方法。
5)实体的阶层
同样是谓词,但是与=、BETWEEN等相比,EXISTS的用法还是大不相同的。概括来说,区别在于“谓词的参数可以取什么值”。=、Between 我们只能使用单一值而 Exists 的参数我们取的是行数据的集合。

从上面的图表我们可以知道,EXISTS的特殊性在于输入值的阶数(输出值和其他谓词一样,都是真值)。谓词逻辑中,根据输入值的阶数对谓词进行分类。=或者BETWEEEN等输入值为一行的谓词叫作“一阶谓词”,
而像EXISTS这样输入值为行的集合的谓词叫作“二阶谓词”。阶(order)是用来区分集合或谓词的阶数的概念。
三阶谓词=输入值为“集合的集合”的谓词四阶谓词=输入值为“集合的集合的集合”的谓词……

SQL中采用的是狭义的“一阶谓词逻辑”,这是因为SQL里的EXISTS谓词最高只能接受一阶的实体作为参数。如果想要支持二阶、三阶等更高阶的实体,SQL必须提供相应的支持。理论上这也是可以做到的,只是目前还没有实现。
6)全称量化和存在量化
谓词逻辑中有量词(限量词、数量词)这类特殊的谓词。我们可以用它们来表达一些这样的命题:“所有的x都满足条件P”或者“存在(至少一个)满足条件P的x”。前者称为“全称量词”,后者称为“存在量词”,
分别记作∀、∃。这两个符号看起来很奇怪。其实,全称量词的符号其实是将字母A上下颠倒而形成的,存在量词则是将字母E左右颠倒而形成的。“对于所有的x, ……”的英语是“for All x,…”,而“存在满足……的x”的英语是“there Exists x that…”,
这就是这两个符号的由来。
SQL中的EXISTS谓词实现了谓词逻辑中的存在量词却不存在全称量词。不过二者是可以相互转换的,有如下定义:
∀ xPx = ¬ ∃ x¬P(所有的x都满足条件P=不存在不满足条件P的x)
∃ xPx = ¬ ∀ x¬Px(存在x满足条件P=并非所有的x都不满足条件P)
例1:查询“没有参加某次会议的人”

/*法一:查询没有参加某次会议的人*/
SELECT
temp.`meeting`,
temp.`person`
FROM
(SELECT
* FROM
(SELECT DISTINCT person FROM Meetings)a,(SELECT DISTINCT meeting FROM Meetings)b)temp
LEFT JOIN Meetings c ON temp.meeting = c.meeting AND temp.person = c.person
WHERE c.person IS NULL /*法二:查询没有参加某次会议的人*/
SELECT DISTINCT
a.`meeting`,b.person
FROM Meetings a,Meetings b
WHERE NOT EXISTS
(
SELECT * FROM Meetings c WHERE a.`meeting` = c.meeting AND c.`person` = b.person
)
例2:全称量化
1.“肯定⇔双重否定”之间的转换 请查询出“所有科目分数都在50分以上的学生”

查询“所有科目分数都在50分以上的学生” 转换 查询 “没有一个科目分数不满50分”
/*查询所有科目分数50分以上*/
SELECT DISTINCT student_id
FROM TestScores TS1
WHERE NOT EXISTS
(
SELECT * FROM TestScores TS2
WHERE TS2.student_id = TS1.student_id
AND TS2.score < 50)
接下来我们把条件改得复杂一些再试试。
请查询“某个学生的所有行数据中,如果科目是数学,则分数在80分以上;如果科目是语文,则分数在50分以上。”
/* 全称量化(1):习惯“肯定<=>双重否定”之间的转换 */
SELECT student_id
FROM TestScores TS1
WHERE subject IN ('数学', '语文')
AND NOT EXISTS
(SELECT *
FROM TestScores TS2
WHERE TS2.student_id = TS1.student_id
AND 1 = CASE WHEN subject = '数学' AND score < 80 THEN 1
WHEN subject = '语文' AND score < 50 THEN 1
ELSE 0 END)
GROUP BY student_id
HAVING COUNT(*) = 2; /* 必须两门科目都有分数 */
例3:查询出哪些项目已经完成到了工程1

having子句解题:
--having 子句
/*查询哪些项目已经完成到了工程1*/
SELECT
a.project_id
FROM Projects a
GROUP BY a.project_id
HAVING COUNT(*) = SUM(CASE WHEN step_nbr <= 1 AND STATUS = '完成' THEN 1
WHEN step_nbr >1 AND STATUS = '等待' THEN 1
ELSE 0 END)
exists子句解题:
/*查询哪些项目已经完成到了工程1*/
/*--->查询不存在哪些项目没有完成工程1以及完成过了工程1*/
法一:
SELECT
*
FROM Projects a
WHERE NOT EXISTS (
SELECT STATUS
FROM Projects b
WHERE a.project_id = b.project_id
AND STATUS <> CASE WHEN step_nbr <= 1 THEN '完成' ELSE '等待' END
)
法二:
SELECT
*
FROM Projects b
WHERE NOT EXISTS(
SELECT
*
FROM
Projects a WHERE a.project_id = b.project_id AND(
(step_nbr > 1 AND STATUS = '完成') OR (step_nbr = 1 AND STATUS = '等待'))
)
例四:查询现在能出勤的队伍

having子句:
/*查询可以出勤的队伍 having*/
SELECT
a.`team_id`
FROM
Teams a
GROUP BY a.`team_id`
HAVING COUNT(*) = (SELECT COUNT(*) FROM Teams b WHERE a.`team_id` = b.`team_id` AND b.`status` = '待命')
exists 子句:
/*查询可以出勤的队伍 全称量化*/
/*队伍中不存在不是待命的队员*/
SELECT
*
FROM
Teams a WHERE NOT EXISTS (
SELECT * FROM Teams b WHERE a.`team_id` = b.`team_id` AND b.`status` <> '待命'
)
例五:查询存在重复材料的生产地

having子句:
/*查询存在重复材料的生产地 having*/
SELECT
a.center
FROM
Materials a
GROUP BY a.center
HAVING COUNT(*) <> COUNT(DISTINCT a.material)
exists子句:
/*存在重复的生产地*/
SELECT
*
FROM
Materials a
WHERE EXISTS (
SELECT * FROM Materials b WHERE a.center = b.`center` AND a.receive_date <> b.`receive_date` AND a.material = b.`material`
)
例六:查询出75%以上的学生分数都在80以上的班级。

/*请查询出75%以上的学生分数都在80分以上的班级*/
SELECT b.class FROM TestResults b
GROUP BY b.class
HAVING SUM(CASE WHEN score>=80 THEN 1 ELSE 0 END)/COUNT(*) > 0.75
例7:找出连续为3个空位的组合


/*全是被未预订的座位*/
/*--->不存在不是被未预订的座位*/
SELECT
*
FROM Seats a,Seats b
WHERE b.seat = a.seat + 2
AND NOT EXISTS (
SELECT *
FROM Seats c
WHERE c.`seat` BETWEEN a.seat AND b.seat AND c.`status` <> '未预订'
)
SQL进阶总结(一)的更多相关文章
- pl/sql进阶--例外处理
在pl/sql的执行过程中发生异常时系统所作的处理称为一个例外情况(exception).通常例外情况的种类有三种: 1.预定义的oracle例外情况oracle预定义的例外情况大约有24个,对于这种 ...
- SQL进阶随笔--case用法(一)
SQL进阶一整个是根据我看了pdf版本的整理以及自己的见解整理.后期也方便我自己查看和复习. CASE 表达式 CASE 表达式是从 SQL-92 标准开始被引入的.可能因为它是相对较新的技术,所以尽 ...
- 【SQL进阶】03.执行计划之旅1 - 初探
听到大牛们说执行计划,总是很惶恐,是对知识的缺乏的惶恐,所以必须得学习执行计划,以减少对这一块知识的惶恐,下面是对执行计划的第一讲-理解执行计划. 本系列[T-SQL]主要是针对T-SQL的总结. S ...
- pl/sql进阶一控制结构
在任何计算机语言(c,java,c#,c++)都有各种控制语句(条件语句,循环结构,顺序控制结构…),在pl/sql中也存在这样的控制结构. 在本部分学校完毕后,希望大家达到: 1)使用各种if语句 ...
- 《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 ...
- 二十五、oracle pl/sql进阶--控制结构(分支,循环,控制)
一.pl/sql的进阶--控制结构在任何计算机语言(c,java,pascal)都有各种控制语句(条件语句,循环结构,顺序控制结构...),在pl/sql中也存在这样的控制结构.在本部分学习完成后,希 ...
- mysql基础sql进阶
回顾前面的基础命令语句 修改数据表 添加字段: alter table 表名 add 字段名 列类型[not null|null][primary key][unique][auto_incremen ...
随机推荐
- 一个DDOS病毒的分析(二)
一.基本信息 样本名称:hra33.dll或者lpk.dll 样本大小: 66560 字节 文件类型:Win32的dll文件 病毒名称:Dropped:Generic.ServStart.A3D47B ...
- hdu4995 (不错的小模拟)
题意: 输入n,m,k ,给你n个点,他们在一个一维坐标上,每个点有两个值,一个是坐标,另一个是价值,然后有m组操作,每次操作给一个坐标,意思就是把当前这个坐标的点距离他最近的k个点(相等 ...
- hdu4915 判断括号匹配
题意: 问你括号匹配是否唯一,三种字符'(','?',')',问号可以变成任何字符. 思路: 首先我们要学会判断当前串是否成立?怎么判断?我的方法是跑两遍,开三个变变量 s1 ...
- Windows Server系统加固
目录 账户管理.认证授权 管理账户 管理口令 授权 审核策略 IP协议安全配置 设备其他配置操作 账户管理.认证授权 管理账户 说明: 对于管理员账号,要求更改缺省账户名称,并且禁用 guest (来 ...
- POJ2044 深搜+剪枝(云彩下雨)
题意: 有一个城镇,是4*4的大小的,然后你控制一块云彩,2*2的,你每天可以有9种走的方法,上下左右,或者不动,走的时候可以走1或者2步,云彩所在的地方肯定会下雨,然后给你做多365天 ...
- W32Dasm缓冲区溢出分析【转载】
课程简介 在上次课程中与大家一起学习了编写通用的Shellcode,也提到会用一个实例来展示Shellcode的溢出. 那么本次课程中为大家准备了W32Dasm这款软件,并且是存在漏洞的版本.利用它的 ...
- PowerShell-4.API调用以及DLL调用
PowerShell可以直接调用API,So...这东西完全和cmd不是一回事了... 调用API的时候几乎和C#一样(注意堆栈平衡): 调用MessageBox: $iii = Add-Type - ...
- Run-Time Check Failure #0,The value of ESP was not properly saved 错误解决
调用DLL函数,出现错误 Run-Time Check Failure #0 - The value of ESP was not properly saved across a function c ...
- SSRF_FastCGI
SSRF_FastCGI 目录 SSRF_FastCGI FastCGI协议 SSRF ssrf + fastcgi 参考 FastCGI协议 简介 Fast CGI源自旧版本的CGI 路由/结构图 ...
- js实现倒计时函数
function updateEndTime() { //当前时间,距1970年1月1日的秒数 var date = new Date(); var time = (date.getTime())/1 ...