当前位置: 首页 > 面试题库 >

从数据库模型中消除NULLable列的选项(以避免SQL的三值逻辑)?

东门理
2023-03-14
问题内容

前一段时间,我一直在阅读CJ Date撰写的《
SQL和关系理论

》一书。作者因批评SQL的三值逻辑(3VL)而闻名。 1)

作者对为什么在SQL中应避免使用3VL提出了一些强点,但是他没有概述 如果不允许使用可空列,那么数据库模型的外观
。我已经对此进行了思考,并提出了以下解决方案。如果我错过了其他设计方案,我想听听他们的意见!

1) Date对SQL 3VL的评论也遭到批评:参见Claude
Rubinson的这篇论文(包括CJ Date的原始评论)。

表格示例:

以下表为例,其中有一个可为空的列(DateOfBirth):

#  +-------------------------------------------+
#  |                   People                  |
#  +------------+--------------+---------------+
#  |  PersonID  |  Name        |  DateOfBirth  |
#  +============+--------------+---------------+
#  |  1         |  Banana Man  |  NULL         |
#  +------------+--------------+---------------+

选项1:NULL通过标志和默认值进行仿真:

而不是使该列为可空,而是指定了任何默认值(例如1900-01-01)。另一BOOLEAN列将指定是DateOfBirth仅应忽略其中的值还是实际上包含数据。

#  +------------------------------------------------------------------+
#  |                              People'                             |
#  +------------+--------------+----------------------+---------------+
#  |  PersonID  |  Name        |  IsDateOfBirthKnown  |  DateOfBirth  |
#  +============+--------------+----------------------+---------------+
#  |  1         |  Banana Man  |  FALSE               |  1900-01-01   |
#  +------------+--------------+----------------------+---------------+

选项2:将可为空的列转换为单独的表:

可为空的列由新表(DatesOfBirth)代替。如果记录中没有该列的数据,则新表中将没有记录:

#  +---------------------------+ 1    0..1 +----------------------------+
#  |         People'           | <-------> |         DatesOfBirth       |
#  +------------+--------------+           +------------+---------------+
#  |  PersonID  |  Name        |           |  PersonID  |  DateOfBirth  |
#  +============+--------------+           +============+---------------+
#  |  1         |  Banana Man  |
#  +------------+--------------+

尽管这似乎是更好的解决方案,但可能会导致许多表需要为单个查询连接。由于OUTER JOIN将不允许s(因为它们会引入NULL到结果集中),因此像以前一样,仅通过单个查询就可能不再获取所有必需的数据。

问题: 是否还有其他消除方法NULL(如果是的话,它们是什么)?


问题答案:

我看到Date的同事Hugh Darwen在出色的演讲“如何在不使用NULL的情况下处理丢失的信息”中讨论了此问题,该演讲可在Third
Manifesto网站上找到

他的解决方案是您第二种方法的变体。这是第六种普通形式,其中的表用于保存出生日期和未知的标识符:

#  +-----------------------------+ 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          |
#                                            +------------+

然后,从“人员”中进行选择需要将所有三个表(包括样板)结合起来以指示未知的出生日期。

当然,这是理论上的。如今,SQL的状态仍不足以处理所有这些问题。休的演讲涵盖了这些缺点。他提到的一件事并不完全正确:某些SQL版本确实支持多重赋值-
例如Oracle的INSERT
ALL语法。



 类似资料:
  • 我认为这是一个常见的问题,但我还没有找到任何解决方案,也许我没有在谷歌上正确地搜索这个问题。总之,我有一个在表中插入多行的过程(在同一个事务中的许多其他事情中),但是这个过程是在多个线程和多个服务器中执行的。 描述是唯一的,但不作为数据库(旧版)中的约束,我想避免插入重复的描述。我已经隔离了搜索并插入到一个独立的事务中,我想在选择之前锁定表,如果它不存在,则在“保存”之后释放它。 我想要这样的东西

  • 问题内容: 是否可以检索中特定行的特定列? 假设我要使用以下查询文本从名为的表中选择名称为:a,b的行: 如何修改此查询文本以仅选择第2、12、22、32、42列,而不是选择其所有1000列? 问题答案: 将通配符替换为要检索的列名。 但是请阅读有关SQL标准的文档。您在表中需要1.000列的可能性很小。

  • 我有下一个示例代码: 你可以看到id是JSON格式中的一个重复字段,我知道PostgreSQL有一些功能可以避免这个问题,但我找不到。

  • 我正试图从数据库中删除一行,但得到以下错误

  • 我从一个用spark-kafka-cassandra(在kubernetes上)重写猛犸象spark-kafka-hbase应用程序的初步想法开始。 我有以下数据模型,一个支持全时插入,另一个支持upserts 办法1: 创建表test.inv_positions( location_id int, item bigint, time_id timestamp, sales_floor_qty i

  • 问题内容: 我有此错误信息: 消息8134,级别16,状态1,第1行除以零错误。 编写SQL代码的最佳方法是什么,这样我就再也看不到此错误消息了? 我可以执行以下任一操作: 添加一个where子句,这样我的除数永远不会为零 或者 我可以添加一个case语句,以便对零进行特殊处理。 使用子句的最佳方法是吗? 有没有更好的方法,或者如何执行? 问题答案: 为了避免出现“被零除”错误,我们对此进行了如下