正确使用 NULL,并利用业务逻辑与存储过程的 CHECK 约束

The*_*uad 2 null database-design constraint stored-procedures

这个问题是关于 NULL 的正确使用和对业务逻辑与存储过程的 CHECK 约束的使用。

我有以下表格设置。

实体关系图

我对表进行了标准化以避免使用 NULL。问题是这些表中的一些由于业务流程而相互依赖。有些设备必须经过消毒,有些设备在另一个系统中进行跟踪。所有设备最终都将在处置表中处置。

问题是我需要执行检查,例如如果布尔字段RequiresSantization为真,则在DisposalDate输入Sanitize字段之前无法输入。

此外,如果布尔值为IsTrackedInOther真,则OfficialOutOfService必须先输入字段,然后DisposalDate才能输入。

如果我将所有这些列合并到Archive.Device表中,那么我将拥有 NULL 字段,但我将能够使用 CHECK 约束管理所有业务规则。

另一种方法是让表保持原样,并通过从表中选择以检查记录是否存在,然后抛出适当的错误来管理存储过程中的业务逻辑。

这是可以适当使用 NULL 的情况吗?布尔领域IsTrackedInOtherRequiresSanitization基本赋予意义的NULL字段。如果IsTrackedInOther是,false则设备未在其他系统中跟踪SectionID并且SpecialDeviceCode为 NULL,我知道它们应该为 NULL,因为它未在其他系统中跟踪。同样,OfficialOutOfServiceDateOOSLogPath我知道会是NULL藏汉,并且DisposalDate可以随时进入。

如果IsTrackedInOthertrue,那么SectionIDSpecialDeviceCode将是必需的,如果OfficialOutOfServiceDateOOSLogPath是NULL,那么我知道它们还没有被正式从该系统中删除,因此DisposalDate在输入它们之前不能有a 。

所以这是一个问题

单独的表/无 NULL/在存储过程中强制执行规则

对比

在 CHECK 约束中组合表/NULLs/强制规则。

我知道在图片中使用 NULL 进行查询可能很复杂并且有一些未定义的行为,因此从这个意义上讲,单独的表和存储过程似乎是有益的。或者,能够使用 CHECK 约束并将规则内置到表中似乎同样有益。

有什么想法吗?谢谢阅读。请在需要时要求澄清。

如果它们被合并并且我允许 NULL,则更新示例表。

* = Allow NULL

+-------------------------+
|Archive.Device Table     |
+-------------------------+
|DeviceID                 |
|SerialNumber             |
|DeviceTypeID             |
|IsTrackedInOther         |
|SectionID*               |
|SpecialDeviceCode*       |
|OfficialOutOfServiceDate*|
|OOSLogPath*              |
|OOSRemarks*              |
|RequiresSanitization     |
|SanitizeMethodID*        |
|SanitizeLogPath*         |
|SanitizeDate*            |
|SanitizeRemarks*         |
|Location                 |
|OriginalInventoryDate    |
|ArchiveDate              |
|LastUpdated              |
|ReasonID                 |
|StorageLocation          |
|ArchiveRemarks           |
|CategoryCode             |
+-------------------------+
Run Code Online (Sandbox Code Playgroud)

示例检查:

IsTrackedInOther = 0 AND SectionID IS NULL AND SpecialDeviceCode IS NULL AND 
OfficialOutOfServiceDate IS NULL AND OOSLogPath IS NULL AND OOSRemarks IS NULL
OR IsTrackedInOther = 1 AND SectionID IS NOT NULL AND SpecialDeviceCode IS NOT NULL
Run Code Online (Sandbox Code Playgroud)

这似乎是处理这个问题的自然方法,还是设计问题?

Lei*_*fel 6

查询可以包含空值的列比查询不能包含空值的列更复杂。查询多个表也比查询一个表更复杂。我不会让避免空驱动规范化。

例如,您提到所有设备最终都会被处置并获得处置日期。如果 Disposal 表中没有其他列,那么在我看来,将 DisposalDate 放在 Device 表中更有意义。Sanitize 等其他表作为单独的表可能更有意义,因为有多个数据点不适用于某些设备。

检查约束很好,应该在可能的情况下使用,但总有一些时候需要一个过程。