写在前面

支撑SQL和关系数据库的基础理论:数学领域的集合论逻辑学标准体系的谓词逻辑

理论篇

  • 什么是谓词?谓词是返回值为真值(true false unknown)的函数

    关系数据库里,每一个行数据可以看作是一个命题

  • 实体的阶层

    0阶实体(单行) -- 1阶谓词( = between and)

    1阶实体(行集合/表) -- 2阶谓词 (exists)

    2阶实体(表的集合) -- 3阶谓词 1970被毙掉,目前数据库均以二阶谓词为基准

  • 全称量化与存在量化

    • 全称量词:所有的\(x\)都满足条件\(P\)
    • 存在量词:存在(至少有一个)满足条件\(P\)的\(x\)
    • EXISTS谓词实现了存在量词(因此,可以根据德摩根律实现全称量化)

实践篇

查询表中不存在的数据

  1. /* 查询表中“不”存在的数据 */
  2. CREATE TABLE Meetings
  3. (meeting CHAR(32) NOT NULL,
  4. person CHAR(32) NOT NULL,
  5. PRIMARY KEY (meeting, person));
  6. INSERT INTO Meetings VALUES('第1次', '伊藤');
  7. INSERT INTO Meetings VALUES('第1次', '水岛');
  8. INSERT INTO Meetings VALUES('第1次', '坂东');
  9. INSERT INTO Meetings VALUES('第2次', '伊藤');
  10. INSERT INTO Meetings VALUES('第2次', '宫田');
  11. INSERT INTO Meetings VALUES('第3次', '坂东');
  12. INSERT INTO Meetings VALUES('第3次', '水岛');
  13. INSERT INTO Meetings VALUES('第3次', '宫田');
  1. -- 求所有人参加所有会的笛卡尔积
  2. SELECT DISTINCT m1.meeting,m2.person FROM Meetings AS m1 CROSS JOIN Meetings AS m2;
  1. -- 求出缺席者的SQL语句(1):存在量化的应用
  2. SELECT DISTINCT m1.meeting,m2.person
  3. FROM Meetings AS m1 CROSS JOIN Meetings AS m2
  4. WHERE NOT EXISTS (SELECT * FROM Meetings AS m3 WHERE m1.meeting = m3.meeting AND m2.person = m3.person);
  1. -- 求出缺席者的SQL语句(2):使用差集运算
  2. SELECT m1.meeting,m2.person
  3. FROM Meetings AS m1,Meetings AS m2
  4. EXCEPT
  5. SELECT meeting,person
  6. FROM Meetings;

全称量词(1):习惯"肯定 \(\Leftrightarrow\) 双重否定"之间的转换

  1. /* 全称量化(1):习惯“肯定<=>双重否定”之间的转换 */
  2. CREATE TABLE TestScores
  3. (student_id INTEGER,
  4. subject VARCHAR(32) ,
  5. score INTEGER,
  6. PRIMARY KEY(student_id, subject));
  7. INSERT INTO TestScores VALUES(100, '数学',100);
  8. INSERT INTO TestScores VALUES(100, '语文',80);
  9. INSERT INTO TestScores VALUES(100, '理化',80);
  10. INSERT INTO TestScores VALUES(200, '数学',80);
  11. INSERT INTO TestScores VALUES(200, '语文',95);
  12. INSERT INTO TestScores VALUES(300, '数学',40);
  13. INSERT INTO TestScores VALUES(300, '语文',90);
  14. INSERT INTO TestScores VALUES(300, '社会',55);
  15. INSERT INTO TestScores VALUES(400, '数学',80);
  1. -- 查出所有科目分数都在50分以上的学生
  2. SELECT DISTINCT student_id FROM TestScores AS TS1
  3. WHERE NOT EXISTS (SELECT * FROM TestScores AS TS2 WHERE TS2.student_id
  4. = TS1.student_id AND TS2.score < 50) -- 仅就本题而言,还可以使用min(score)>=50
  1. -- 查找出数学分数>=80,语文分数>=50的学生
  2. SELECT DISTINCT student_id FROM TestScores AS TS1
  3. WHERE subject IN ('数学','语文') AND NOT EXISTS (SELECT * FROM TestScores AS TS2 WHERE TS2.student_id
  4. = TS1.student_id AND 1 = CASE WHEN subject = '数学' AND score < 80 THEN 1
  5. WHEN subject = '语文' AND score < 50 THEN 1 ELSE 0 END)
  6. GROUP BY student_id
  7. HAVING COUNT(*) = 2; -- group by having 子句要求两门课程都要有成绩

全称量化(2):集合和谓词,哪个更强大?

  1. /* 全称量化(2):集合VS谓词——哪个更强大? */
  2. CREATE TABLE Projects
  3. (project_id VARCHAR(32),
  4. step_nbr INTEGER ,
  5. status VARCHAR(32),
  6. PRIMARY KEY(project_id, step_nbr));
  7. INSERT INTO Projects VALUES('AA100', 0, '完成');
  8. INSERT INTO Projects VALUES('AA100', 1, '等待');
  9. INSERT INTO Projects VALUES('AA100', 2, '等待');
  10. INSERT INTO Projects VALUES('B200', 0, '等待');
  11. INSERT INTO Projects VALUES('B200', 1, '等待');
  12. INSERT INTO Projects VALUES('CS300', 0, '完成');
  13. INSERT INTO Projects VALUES('CS300', 1, '完成');
  14. INSERT INTO Projects VALUES('CS300', 2, '等待');
  15. INSERT INTO Projects VALUES('CS300', 3, '等待');
  16. INSERT INTO Projects VALUES('DY400', 0, '完成');
  17. INSERT INTO Projects VALUES('DY400', 1, '完成');
  18. INSERT INTO Projects VALUES('DY400', 2, '完成');
  1. -- 查询完成到了工程1的项目 having子句解法
  2. SELECT product_id FROM Projects GROUP BY project_id HAVING COUNT(*) = SUM(CASE WHEN step_nbr <= AND status = '完成' THEN 1 WHEN step_nbr > 1 AND status = '等待' THEN 1 ELSE 0 END);
  1. -- 查询完成到了工程1的项目 having子句解法 谓词解法
  2. SELECT * FROM Projects P1 WHERE NOT EXISTS (SELECT status from Projects P2 WHERE P1.project_id = P2.project_id AND status <> CASE WHEN step_nbr <= 1 THEN '完成' ELSE '等待' END);
  3. -- 劣势:双重否定,不易理解;优势:性能好,只要有一个行满足条件,查询就会终止;包含的信息更全

对列进行量化:查询全是1的行

  1. /* 对列进行量化:查询全是1的行 */
  2. CREATE TABLE ArrayTbl
  3. (keycol CHAR(1) PRIMARY KEY,
  4. col1 INTEGER,
  5. col2 INTEGER,
  6. col3 INTEGER,
  7. col4 INTEGER,
  8. col5 INTEGER,
  9. col6 INTEGER,
  10. col7 INTEGER,
  11. col8 INTEGER,
  12. col9 INTEGER,
  13. col10 INTEGER);
  14. --全为NULL
  15. INSERT INTO ArrayTbl VALUES('A', NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL);
  16. INSERT INTO ArrayTbl VALUES('B', 3, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL);
  17. --全为1
  18. INSERT INTO ArrayTbl VALUES('C', 1, 1, 1, 1, 1, 1, 1, 1, 1, 1);
  19. --至少有一个9
  20. INSERT INTO ArrayTbl VALUES('D', NULL, NULL, 9, NULL, NULL, NULL, NULL, NULL, NULL, NULL);
  21. INSERT INTO ArrayTbl VALUES('E', NULL, 3, NULL, 1, 9, NULL, NULL, 9, NULL, NULL);
  1. -- "列方向"的全称量化:查找全是1的行 不优雅的解答
  2. SELECT * FROM ArrayTbl WHERE col1 = 1 AND col2 = 1 AND col3 = 1 AND col4 = 1 AND col5 = 1
  3. AND col6 = 1 AND col7 = 1 AND col8 = 1 AND col9 = 1 AND col10 = 1;
  4. -- "列方向"的全称量化:查找全是1的行 优雅的解答
  5. SELECT * FROM ArrayTbl WHERE 1 = ALL (values(col1),(col2),(col3),(col4),(col5),(col6),(col7),(col8),(col9),(col10));
  6. -- "列方向"的全称量化:查找某一列是9的行
  7. SELECT * FROM ArrayTbl WHERE 9 = ANY (values(col1),(col2),(col3),(col4),(col5),(col6),(col7),(col8),(col9),(col10));
  8. -- "列方向"的全称量化:查找某一列是9的行
  9. SELECT * FROM ArrayTbl WHERE 9 IN (col1,col2,col3,col4,col5,col6,col7,col8,col9,col10);
  10. -- 查找全是NULL的行
  11. SELECT * FROM ArrayTbl WHERE COALESCE(col1,col2,col3,col4,col5,col6,col7,col8,col9,col10) IS NULL;

小结

  • SQL中的谓词指的是返回真值的函数
  • EXISTS与其他谓词不同,接受的参数是集合
  • 因此EXISTS可以看成一种高阶函数
  • SQL没有与全称量词相当的谓词,可以使用NOT EXISTS代替

练习题

  1. /* 练习题1-8-1:数组表——行结构表的情况 */
  2. CREATE TABLE ArrayTbl2
  3. (key CHAR(1) NOT NULL,
  4. i INTEGER NOT NULL,
  5. val INTEGER,
  6. PRIMARY KEY (key, i));
  7. /* A全为NULL、B仅有一个为非NULL、C全为非NULL */
  8. INSERT INTO ArrayTbl2 VALUES('A', 1, NULL);
  9. INSERT INTO ArrayTbl2 VALUES('A', 2, NULL);
  10. INSERT INTO ArrayTbl2 VALUES('A', 3, NULL);
  11. INSERT INTO ArrayTbl2 VALUES('A', 4, NULL);
  12. INSERT INTO ArrayTbl2 VALUES('A', 5, NULL);
  13. INSERT INTO ArrayTbl2 VALUES('A', 6, NULL);
  14. INSERT INTO ArrayTbl2 VALUES('A', 7, NULL);
  15. INSERT INTO ArrayTbl2 VALUES('A', 8, NULL);
  16. INSERT INTO ArrayTbl2 VALUES('A', 9, NULL);
  17. INSERT INTO ArrayTbl2 VALUES('A',10, NULL);
  18. INSERT INTO ArrayTbl2 VALUES('B', 1, 3);
  19. INSERT INTO ArrayTbl2 VALUES('B', 2, NULL);
  20. INSERT INTO ArrayTbl2 VALUES('B', 3, NULL);
  21. INSERT INTO ArrayTbl2 VALUES('B', 4, NULL);
  22. INSERT INTO ArrayTbl2 VALUES('B', 5, NULL);
  23. INSERT INTO ArrayTbl2 VALUES('B', 6, NULL);
  24. INSERT INTO ArrayTbl2 VALUES('B', 7, NULL);
  25. INSERT INTO ArrayTbl2 VALUES('B', 8, NULL);
  26. INSERT INTO ArrayTbl2 VALUES('B', 9, NULL);
  27. INSERT INTO ArrayTbl2 VALUES('B',10, NULL);
  28. INSERT INTO ArrayTbl2 VALUES('C', 1, 1);
  29. INSERT INTO ArrayTbl2 VALUES('C', 2, 1);
  30. INSERT INTO ArrayTbl2 VALUES('C', 3, 1);
  31. INSERT INTO ArrayTbl2 VALUES('C', 4, 1);
  32. INSERT INTO ArrayTbl2 VALUES('C', 5, 1);
  33. INSERT INTO ArrayTbl2 VALUES('C', 6, 1);
  34. INSERT INTO ArrayTbl2 VALUES('C', 7, 1);
  35. INSERT INTO ArrayTbl2 VALUES('C', 8, 1);
  36. INSERT INTO ArrayTbl2 VALUES('C', 9, 1);
  37. INSERT INTO ArrayTbl2 VALUES('C',10, 1);
  1. /* 正确解法 */
  2. SELECT DISTINCT key
  3. FROM ArrayTbl2 A1
  4. WHERE NOT EXISTS
  5. (SELECT *
  6. FROM ArrayTbl2 A2
  7. WHERE A1.key = A2.key
  8. AND (A2.val <> 1 OR A2.val IS NULL));
  1. /* 其他解法1:使用ALL谓词 */
  2. SELECT DISTINCT key
  3. FROM ArrayTbl2 A1
  4. WHERE 1 = ALL
  5. (SELECT val
  6. FROM ArrayTbl2 A2
  7. WHERE A1.key = A2.key);
  1. /* 其他解法2:使用HAVING子句 */
  2. SELECT key
  3. FROM ArrayTbl2
  4. GROUP BY key
  5. HAVING SUM(CASE WHEN val = 1 THEN 1 ELSE 0 END) = 10;
  1. /* 其他解法3:在HAVING子句中使用极值函数 */
  2. SELECT key
  3. FROM ArrayTbl2
  4. GROUP BY key
  5. HAVING MAX(val) = 1
  6. AND MIN(val) = 1;
  1. /* 练习题1-8-2:使用ALL谓词进行全称量化
  2. 查找已经完成到工程1的项目:使用ALL谓词解答 */
  3. SELECT *
  4. FROM Projects P1
  5. WHERE '○' = ALL
  6. (SELECT CASE WHEN step_nbr <= 1 AND status = '完成' THEN '○'
  7. WHEN step_nbr > 1 AND status = '等待' THEN '○'
  8. ELSE '×' END
  9. FROM Projects P2
  10. WHERE P1.project_id = P2. project_id);
  1. /* 练习题1-8-3:求(1-100)中的质数 */
  2. SELECT num AS prime
  3. FROM Numbers Dividend
  4. WHERE num > 1
  5. AND NOT EXISTS
  6. (SELECT *
  7. FROM Numbers Divisor
  8. WHERE Divisor.num <= Dividend.num / 2 /* 除了自身之外的约数必定小于等于自身值的一半 */
  9. AND Divisor.num <> 1 /* 约数中不包含1 */
  10. AND MOD(Dividend.num, Divisor.num) = 0) /*“除不尽”的否定条件是“除尽” */
  11. ORDER BY prime;

SQL进阶系列之8EXISTS谓词的用法的更多相关文章

  1. SQL进阶系列之5外连接的用法

    写在前面 SQL本身是作为一种数据提取工具而出现,使用SQL生成各种定制化报表和非定制化报表并非SQL原本用途的功能,但这并不意味着SQL无法实现这些功能. 用外连接进行行列转换(1)(行 → 列): ...

  2. SQL进阶系列之7用SQL进行集合运算

    写在前面 集合论是SQL语言的根基,因为这种特性,SQL也被称为面向集合语言 导入篇:集合运算的几个注意事项 注意事项1:SQL能操作具有重复行的集合(multiset.bag),可以通过可选项ALL ...

  3. SQL进阶1:case表达式的用法示例

    一:case表达式的用法 1.SQL中的case表达式的作用是用来对"某个变量"进行某种转化,通常在select字句中使用,举个例子: 不能看出,case表达式很像我们的if el ...

  4. SQL进阶系列之11让SQL飞起来

    写在前面 SQL的性能优化是数据库使用者必须面对的重要问题,本节侧重SQL写法上的优化,SQL的性能同时还受到具体数据库的功能特点影响,这些不在本节讨论范围之内 使用高效的查询 参数是子查询时,使用E ...

  5. SQL进阶系列之9用SQL处理数列

    写在前面 关系模型的数据结构里,并没有顺序的概念,但SQL处理有序集合也有坚实的理论基础 生成连续编号 --生成连续编号 CREATE TABLE Digits (digit INTEGER PRIM ...

  6. SQL进阶系列之4HAVING字句的力量

    写在前面 SQL是面向集合的语言,与面向过程和面向对象语言都不一样 寻找缺失的编号 /* 寻找缺失的编号 */ CREATE TABLE SeqTbl (seq INTEGER PRIMARY KEY ...

  7. SQL进阶系列之3三值逻辑与NULL

    写在前面 普通编程语言里的布尔型只有true和false两个值,这种逻辑体系被称为二值逻辑,而SQL语言里,还有第三个值unknown,因此SQL的逻辑体系被称为三值逻辑. Why SQL存在三值逻辑 ...

  8. SQL进阶系列之1CASE表达式

    配置环境: 下载地址:https://www.enterprisedb.com/downloads/postgres-postgresql-downloads#windows 使用数据库: C:\Po ...

  9. Linq To Sql进阶系列(六)用object的动态查询与保存log篇

    动态的生成sql语句,根据不同的条件构造不同的where字句,是拼接sql 字符串的好处.而Linq的推出,是为了弥补编程中的 Data != Object 的问题.我们又该如何实现用object的动 ...

随机推荐

  1. Ubuntu tricks

    linux 复制文件夹内所有文件到另一个文件夹 cp -Rf /home/user1/* /root/temp/ 将 /home/user1目录下的所有东西拷到/root/temp/下而不拷贝user ...

  2. Linux 就该这么学 CH02新手必须掌握的Linux命令

    0 概述 本章内容如下 强大的shell. 帮助文档命令(1) 系统工作命令(10) 系统状态监测命令(8) 工作目录切换命令(3) 文本文件编辑命令(9) 文件目录管理命令(7) 打包压缩或搜索命令 ...

  3. Toping Kagglers:Bestfitting,目前世界排名第一

    Toping Kagglers:Bestfitting,目前世界排名第一 Kaggle团队 |2018年5月7日   我们在排行榜上排名第一 - 这是两年前令人惊讶地加入该平台的竞争对手.Shubin ...

  4. Linux下使用matlab在后台默默的运行.m文件(无界面形式)

    Linux下使用matlab在后台默默的运行.m文件(无界面形式)本主在Ubuntu18.04LTS上已经安装了matlab直接运行Matlab$ matlab会启动 matlab,出现启动界面但想要 ...

  5. SQL Server 数据库启动过程(用户数据库加载过程的疑难杂症)

    前言 本篇主要是上一篇文章的补充篇,上一篇我们介绍了SQL Server服务启动过程所遇到的一些问题和解决方法,可点击查看,我们此篇主要介绍的是SQL Server启动过程中关于用户数据库加载的流程, ...

  6. Unable to resolve service for type 'Microsoft.Extensions.Logging.ILogger' while attempting to activate 'xxxxx.Controllers.xxxxController'.

    Unable to resolve service for type 'Microsoft.Extensions.Logging.ILogger' while attempting to activa ...

  7. C++静态库与动态库的区别

    在日常开发中,其实大部分时间我们都会和第三方库或系统库打交道.在 Android 开发音视频开发领域,一般会用到 FFmepg.OpenCV.OpenGL 等等开源库, 我们一般都会编译成动态库共我们 ...

  8. redis源码分析(四)--aof持久化

    Redis aof持久化 Redis支持两种持久化方式:rdb与aof,上一篇文章中已经大致介绍了rdb的持久化实现,这篇文章主要介绍aof实现. 与rdb方式相比,aof会使用更多的存储空间,因为它 ...

  9. vue路由懒加载及组件懒加载

    一.为什么要使用路由懒加载 为给客户更好的客户体验,首屏组件加载速度更快一些,解决白屏问题. 二.定义 懒加载简单来说就是延迟加载或按需加载,即在需要的时候的时候进行加载. 三.使用 常用的懒加载方式 ...

  10. vue中引入百度地图

    xxx.vue <template> <div> <el-input v-model="inputaddr"> </el-input> ...