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 ...
随机推荐
- Known Notation 39届亚洲赛牡丹江站K题
题意: 题意,哎!说道题意就蛋疼啊,比赛的时候就愣是把这个题目读成数字可以随意组合,比如123 可以拆成1 23 ,12 3 ,1 2 3,结果显然,水题当神题,各种想不出来,然后就显然的 ...
- Burpsuite工具的使用
目录 Burpsuite Proxy代理模块 Repeater模块(改包,重放) Intruder模块(爆破) Target模块 position模块 Payloads模块 Options模块 一处爆 ...
- UVA11520填充正方形
题意: 给你一个n*n的矩阵,让你往里面添加大写字母,矩阵有的字母已经给填好了,然后要求是每个格子都不能与他相邻的格子的大写字母相同,如果有多个答案,输出从上到下,从左到右所连接的成的那个n ...
- JDBC相关配置和操作
获取数据库连接的几种方式 ps.数据库URL : String url = "jdbc:mysql://localhost:3306/dailytext?useSSL=false&s ...
- 【敏杰开发】Beta阶段项目展示
[敏杰开发]Beta阶段项目展示 项目相关地址汇总 线上地址:http://roadmap.imcoming.top 前端仓库:https://github.com/MinJieDev/Roadmap ...
- [基本运算符、流程控制之if判断、与用户交互、深浅拷贝]
[基本运算符.流程控制之if判断.与用户交互] 基本运算符 1.算数运算符 python支持的算术运算符与数学上计算的符号使用是一致的 salary = 3.3 res = salary * 12 p ...
- 简单聊聊内存逃逸 | 剑指offer - golang
问题 简单讲讲golang的内存逃逸吗? 解析 什么是内存逃逸 在程序中,每个函数块都会有自己的内存区域用来存自己的局部变量(内存占用少).返回地址.返回值之类的数据,这一块内存区域有特定的结构和寻址 ...
- C# 给PDF签名时添加时间戳的2种方法(附VB.NET代码)
在PDF添加签名时,支持添加可信时间戳来保证文档的法律效应.本文,将通过C#程序代码介绍如何添加可信时间戳,可通过2种方法来实现.文中附上VB.NET代码,有需可供参考. 一.程序运行环境 编译环境: ...
- [bug] CDH 安装 哈希验证失败
分析 验证 parcel 文件的哈希值 和 sha 文件不一致:文件损坏,重新下载 和 sha 官网一致:配置httpd文件 参考 哈希值和官网不一致 https://blog.csdn.net/lv ...
- CSS元素的盒类型
一.css简介 CSS是Cascading Style Sheet的缩写,中文称层叠样式表.HTML中的元素都有着自己的属性和默认样式,CSS控制HTML内标签显示不同布局样式.控制对应html标签颜 ...