sta*_*ica 8 sql null relational-database three-valued-logic
不久前,我一直在阅读CJ Date的SQL和关系理论一书.作者因批评SQL的三值逻辑(3VL)而闻名.1)
作者强调了为什么在SQL中应该避免使用3VL,但是他没有概述如果不允许使用可空列的数据库模型的样子.我已经考虑了一点,并提出了以下解决方案.如果我错过了其他设计选项,我想听听他们的意见!
1)日期对SQL 3VL的批评反过来也受到了批评:请参阅 Claude Rubinson撰写的这篇论文(包括CJ Date的原始批评).
示例表:
举个例子,请看下面的表,我们有一个可以为空的列(DateOfBirth):
# +-------------------------------------------+
# | People |
# +------------+--------------+---------------+
# | PersonID | Name | DateOfBirth |
# +============+--------------+---------------+
# | 1 | Banana Man | NULL |
# +------------+--------------+---------------+
Run Code Online (Sandbox Code Playgroud)
选项1:NULL通过标志和默认值进行模拟:
不是使列可为空,而是指定任何默认值(例如1900-01-01).另一BOOLEAN列将指定是否DateOfBirth应该忽略值in 或者它是否实际包含数据.
# +------------------------------------------------------------------+
# | People' |
# +------------+--------------+----------------------+---------------+
# | PersonID | Name | IsDateOfBirthKnown | DateOfBirth |
# +============+--------------+----------------------+---------------+
# | 1 | Banana Man | FALSE | 1900-01-01 |
# +------------+--------------+----------------------+---------------+
Run Code Online (Sandbox Code Playgroud)
选项2:将可为空的列转换为单独的表:
可空列由新表(DatesOfBirth)替换.如果记录没有该列的数据,则新表中不会有记录:
# +---------------------------+ 1 0..1 +----------------------------+
# | People' | <-------> | DatesOfBirth |
# +------------+--------------+ +------------+---------------+
# | PersonID | Name | | PersonID | DateOfBirth |
# +============+--------------+ +============+---------------+
# | 1 | Banana Man |
# +------------+--------------+
Run Code Online (Sandbox Code Playgroud)
虽然这似乎是更好的解决方案,但这可能会导致需要为单个查询加入许多表.由于OUTER JOIN不允许使用s(因为它们会引入NULL结果集),因此可能不再像以前那样使用单个查询来获取所有必需的数据.
问题:
是否有其他消除选择NULL(如果是,它们是什么)?
我看到 Date 的同事 Hugh Darwen 在一篇精彩的演讲“如何在不使用 NULL 的情况下处理缺失信息”中讨论了这个问题,该演讲可以在第三宣言网站上找到。
他的解决方案是第二种方法的变体。它是第六范式,其中的表保存出生日期和未知的标识符:
# +-----------------------------+ 1 0..1 +----------------------------+
# | People' | <-------> | DatesOfBirth |
# +------------+----------------+ +------------+---------------+
# | PersonID | Name | | PersonID | DateOfBirth |
# +============+----------------+ +============+---------------+
# | 1 | Banana Man | ! 2 | 20-MAY-1991 |
# | 2 | Satsuma Girl | +------------+---------------+
# +------------+----------------+
# 1 0..1 +------------+
# <-------> | DobUnknown |
# +------------+
# | PersonID |
# +============+
# | 1 |
# +------------+
Run Code Online (Sandbox Code Playgroud)
然后,从“人员”中进行选择需要连接所有三个表,包括指示未知出生日期的样板。
当然,这有些理论性。目前 SQL 的状态仍然不够先进,无法处理所有这些问题。休的演讲涵盖了这些缺点。他提到的一件事并不完全正确:某些 SQL 风格确实支持多重赋值 - 例如Oracle 的 INSERT ALL 语法。