《SQL基础教程》+ 《SQL进阶教程》 学习笔记 (7)

三值逻辑的真值表(AND)

AND t u f
t   t   u   f  
u   u   u   f  
f   f   f   f  

三值逻辑的真值表(OR)

OR t u f
t   t   t   t  
u   t   u   u  
f   t   u   f  
(9)避免使用 NULL

从上面的叙述,你可以看出 NULL 是有多么特殊和多么容易引起错误了。

NULL 最恐怖的地方就在于即使你认为自己已经完全驾驭它了,但还是一不小心就会被它在背后捅一刀。

1、避免使用的方法

加上 NOT NULL 约束

使用默认值

编号:使用异常编号

例如 ISO 的性别编号中,除了 “1: 男性”,“2: 女性”,还定义了 “0: 未知”,“9: 不适用” 这两个用于异

常情况的编号。

名字:使用“无名氏”

例如名字用 “未知” or “UNKNOWN” 代替,类别用"-"代替。

数值:使用 0

日期:用最大值或最小值代替

例如开始日期和结束日期,可以使用 0000-01-01 或者 9999-12-31。


2、但你无法100%避免

无法完全消除 NULL 的原因是它扎根于关系数据库的底层中。仅靠上面提到的方法并不足够。

例如,使用外连接,或者 SQL-99 中添加的带 CUBE 或 ROLLUP 的 GROUP BY 时,还是很容易引入 NULL 的。


3、结论

因此我们能做的最多也只是 “尽量”去避免 NULL 的产生,并在不得不使用时适当使用

(10)拓展 —— EXISTS vs. IN

注意:由于有 NULL 捣鬼,所以 IN 会返回 true / fasle / unknown,而 EXISTS 只会返回 true / false。因此,IN 和 EXISTS 可以互相替换使用,而 NOT IN 和NOT EXISTS 却不可以。

具体原因可以回去翻阅原书,这里不赘述。


问:那参数是子查询时,用 IN 还是 EXISTS 更好呢?

-- IN SELECT * FROM Class_A WHERE id IN (     SELECT id     FROM Class_B ); -- EXISTS SELECT * FROM Class_A A WHERE EXISTS (     SELECT *     FROM Class_B B     WHERE A.id = B.id );

如果把上例的 Class_A 看成外表,Class_B 看成内表的话。

答:

维度一:从外表和内表的数据行大小的关系来看

1、IN 只执行一次,此内表查出后就缓存了,所以 IN 适合 外表 > 内表 的情况;

2、EXISTS 是针对外表去作循环,每次循环会跟内表作关联子查询,所以 EXISTS 适合 外表 < 内表 的情况;

3、当 内外表 数据差不多大时,IN 与 EXISTS 也差不多。


维度二:索引的角度

EXISTS 可以用到索引,而 IN 不行。所以 EXISTS 更佳。


维度三: 是否全表遍历

针对内表,EXISTS 只要查到一行数据满足条件就会终止遍历,而 IN 必须遍历整个内表。 所以 EXISTS 更佳。


维度四: 可读性

IN 更佳。


综上所述:还是考虑实际情况。但是 EXISTS 替代 IN 提高性能的可能性更大。

1、要想改善 IN 的性能,除了使用 EXISTS,还可以使用连接

2、最近有很多数据库也尝试着改善了 IN 的性能。例如,在 Oracle 数据库中,如果我们使用了建有索引的列,那么即使使用 IN 也会先扫描索引;PostgreSQL 从版本 7.4 起也改善了使用子查询作为 IN 谓词参数时的查询速度。


注意:其实这个问题也可以当成 非关联子查询 vs. 关联子查询 来看待(除了维度三是 EXISTS 特有的优势外,其他的维度都适用)。

3、CASE 表达式

CASE表达式的语法分为简单CASE表达式和搜索CASE表达式两种。

由于 搜索CASE 表达式 包含了 简单CASE 表达式 的全部功能,所以有更强大的表达能力

注意:CASE 表达式是一种表达式而不是语句,CASE 表达式经常会因为同编程语言里的 CASE 混淆而被叫作 CASE 语句,其实是不对的。(你也可以把 CASE 表达式理解成一种函数,运行后会返回值)

编程语言中的 CASE 语句,还有 break 的概念,而 SQL 中的 CASE 表达式没有。


内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/zygdwg.html