一文详解SQL中的三值逻辑


当前第2页 返回上一页

查询 “与 B 班住在东京的学生年龄不同的 A 班学生” 。也就是说,希望查询到的是拉里和伯杰。

-- 查询与 B 班住在东京的学生年龄不同的 A 班学生的 SQL 语句
SELECT *
FROM Class_A
WHERE age NOT IN ( SELECT age FROM Class_B WHERE city = '东京' );

这条 SQL 语句真的能正确地查询到这两名学生吗?遗憾的是不能。结果是空,查询不到任何数据。根据前文所说的规则推导一下吧:

--1. 执行子查询,获取年龄列表
SELECT *
FROM Class_A
WHERE age NOT IN (22, 23, NULL);
--2. 用 NOT 和 IN 等价改写 NOT IN
SELECT *
FROM Class_A
WHERE NOT age IN (22, 23, NULL);

--3. 用 OR 等价改写谓词 IN
SELECT *
FROM Class_A
WHERE NOT ( (age = 22) OR (age = 23) OR (age = NULL) );

--4. 使用德 · 摩根定律等价改写
SELECT *
FROM Class_A
WHERE NOT (age = 22) AND NOT(age = 23) AND NOT (age = NULL);

--5. 用<> 等价改写 NOT 和 =
SELECT *
FROM Class_A
WHERE (age <> 22) AND (age <> 23) AND (age <> NULL);

--6. 对NULL 使用<> 后,结果为unknown
SELECT *
FROM Class_A
WHERE (age <> 22) AND (age <> 23) AND unknown;

--7.如果AND 运算里包含unknown,则结果不为true
SELECT *
FROM Class_A
WHERE false 或 unknown;

所以 上述查询语句 查询不到任何数据。为了得到正确的结果,需要使用 EXISTS 谓词。

-- 正确的SQL 语句:拉里和伯杰将被查询到
SELECT *
FROM Class_A A
WHERE NOT EXISTS ( SELECT * FROM Class_B B WHERE A.age = B.age AND B.city = '东京' );

--1. 在子查询里和NULL 进行比较运算
SELECT *
FROM Class_A A
WHERE NOT EXISTS ( SELECT * FROM Class_B B WHERE A.age = NULL AND B.city = '东京' );

--2. 对NULL 使用“=”后,结果为 unknown
SELECT *
FROM Class_A A
WHERE NOT EXISTS ( SELECT * FROM Class_B B WHERE unknown AND B.city = '东京' );


--3. 如果AND 运算里包含unknown,结果不会是true
SELECT *
FROM Class_A A
WHERE NOT EXISTS ( SELECT * FROM Class_B B WHERE false 或 unknown);


--4. 子查询没有返回结果,因此相反地,NOT EXISTS 为true
SELECT *
FROM Class_A A
WHERE true;

9. 限定谓词和 NULL

-- 查询比 B 班住在东京的所有学生年龄都小的A 班学生 这里会正常返回 拉里
SELECT *
FROM Class_A
WHERE age < ALL ( SELECT age FROM Class_B WHERE city = '东京' );

如果山田年龄不详,就会有问题了。

--1. 执行子查询获取年龄列表
SELECT *
FROM Class_A
WHERE age < ALL ( 22, 23, NULL);


--2. 将ALL 谓词等价改写为AND
SELECT *
FROM Class_A
WHERE (age < 22) AND (age < 23) AND (age < NULL);


--3. 对NULL 使用“<”后,结果变为 unknown
SELECT *
FROM Class_A
WHERE (age < 22) AND (age < 23) AND unknown;

--4. 如果AND 运算里包含unknown,则结果不为true
SELECT *
FROM Class_A
WHERE false 或 unknown;

10. 限定谓词和极值函数不是等价的

将 9 中的表 Class_B 中 山田的年龄改为Null,执行下面的查询

-- 查询比B 班住在东京的年龄最小的学生还要小的A 班学生 
SELECT *
FROM Class_A
WHERE age < ( SELECT MIN(age) FROM Class_B WHERE city = '东京' );

这里仍能正确查询出拉里和伯杰,这是因为,极值函数在统计时会把为 NULL 的数据排除掉。使用极值函数能使 Class_B 这张表里看起来就像不存在 NULL 一样。

区分含义:

  • ALL 谓词:他的年龄比在东京住的所有学生都小 Q1
  • 极值函数:他的年龄比在东京住的年龄最小的学生还要小 Q2

Q1 和 Q2 不等价的情况:

  • 表里存在 NULL 时它们是不等价的
  • 谓词(或者函数)的输入为空集的情况

这里说明一下情况2:B 班里没有学生住在东京。这时,使用 ALL 谓词的SQL 语句会查询到 A 班的所有学生。然而,用极值函数查询时一行数据都查询不到。这是因为,极值函数在输入为空表(空集)时会返回 NULL 。

--1. 极值函数返回NULL
SELECT *
FROM Class_A
WHERE age < NULL;

--2. 对NULL 使用“<”后结果为 unknown
SELECT *
FROM Class_A
WHERE unknown;

11. 聚合函数和 Null

实际上,当输入为空表时返回 NULL 的不只是极值函数,COUNT 以外的聚合函数也是如此。

-- 查询比住在东京的学生的平均年龄还要小的A 班学生的SQL 语句?
SELECT *
FROM Class_A
WHERE age < ( SELECT AVG(age) FROM Class_B WHERE city = '东京' );

没有住在东京的学生时,AVG 函数返回 NULL 。因此,外侧的 WHERE 子句永远是 unknown ,也就查询不到行。

到此这篇关于一文详解SQL 中的三值逻辑的文章就介绍到这了,更多相关SQL三值逻辑内容请搜索


标签:SQL

返回前面的内容

相关阅读 >>

sqlserver数据库升级脚本图文步骤

sql 新增修改 表字段列的类型等

mysql缓存的查询和清除命令使用详解

超全mysql学习笔记

sqlite与mysql区别及优缺点介绍

mysql explain语句的使用示例

sql中带in条件的查询及提高效率

mysqlsql是干什么的?

sql中in的用法是什么

php操作sql server数据库实现表的改查与统计

更多相关阅读请进入《sql》频道 >>


数据库系统概念 第6版
书籍

数据库系统概念 第6版

机械工业出版社

本书主要讲述了数据模型、基于对象的数据库和XML、数据存储和查询、事务管理、体系结构等方面的内容。



打赏

取消

感谢您的支持,我会继续努力的!

扫码支持
扫码打赏,您说多少就多少

打开支付宝扫一扫,即可进行扫码打赏哦

分享从这里开始,精彩与您同在

评论

管理员已关闭评论功能...