考虑这个表结构:
CREATE TABLE [TableA]
(
[PK_ID] int NOT NULL PRIMARY KEY,
[Name] text NOT NULL,
[FK_TableB] int NULL,
[FK_TableC] int NULL,
[Value] single NULL
)
我想在
Name
、FK_TableB
和 FK_TableC
上创建唯一索引,以便这 3 列中的数据保持唯一。遗憾的是,2 个 FK 列可为空,并且 Access 自动忽略 UNIQUE 索引中的 NULL,从而使这成为可能:
Name | FK_TableB | FK_TableC
----------+-----------+-----------
Text1 | NULL | NULL
Text1 | NULL | NULL
我尊重 Access 对于 NULL 是否是可检查值有自己的看法,但在这种情况下,这是令人难以置信的矛盾。在 SQL Server 中创建这样的索引效果非常好,我很想在 Access 中找到一种方法。
这是我迄今为止尝试过(但失败了)/考虑过的:
创建一个验证规则,通过 COUNT 函数检查唯一性。
使用 NZ 函数创建唯一索引,该索引将检查 NULL。
将 FK 列设为必需,并向每个相关表插入默认/类似 NULL 的记录。
插入一个附加列,连接 3 列中的每一列,并创建仅检查新列的 UNIQUE 索引。
我的同事正在考虑为每种可能的情况创建一个表:
Name
Name
和 FK_TableB
Name
、FK_TableB
和 FK_TableC
这是我唯一的解决方案吗?
将 FK 字段设置为必填项,并向每个相关表插入默认/类似 NULL 的记录。
这将是我首选的解决方案,带有 FK
0
。
我不明白维护起来有多么痛苦 - 只需将记录插入相关表中一次,将 FK 默认值从 NULL 更改为 0,然后就可以了。
您可能需要更改一些应用程序逻辑(您现在测试
FK_TableB IS NOT NULL
,然后执行 FK_TableB > 0
)。
恕我直言,这也不是坏习惯,它比可为 null 的 FK 更好。
它可以让您免于进行大量的 OUTER JOIN - 它们可能会产生诸如不可编辑的查询结果或性能不佳之类的问题。
这就是我所说的三值逻辑。 当测试 NULL
与NULL 是否相等时,结果既不是 TRUE 也不是 FALSE,而是第三个逻辑值 UNKNOWN。 如果这看起来像一罐丑陋的蠕虫,那是因为它确实如此。 您在 FK 中采用 NULL
不仅无法为引用的链接提供值,而且还断言此实例中不存在可选关系。 这是一种合理的解释,但并不是索引构建者通常使用的解释。 顺便说一句,对于任何 SQL 数据库,您都会遇到完全相同的问题。解决方案? 好吧,您可以将数据标准化为第六范式,这种形式在标准化讨论中经常被省略。 在 6NF 中,每个可为空列都会分解为两个表,其中一个包含可为空列,另一个不包含可为空列。 结果是每一列都可以标记为不可为空,而不会损失表达能力。
这将帮助您解决您所提到的问题,但这很可能会带来更多麻烦,而不是其价值。
有一个无需编码的解决方案。
索引不适用于 Null 值,但适用于 Empty ("") 值。 将第二个字段设置为“禁止空”和“允许空字符串”,作为解决方案,将“”设置为其默认值。
插入新记录时,第二个字段将设置为空,索引将按照预期插入或不插入。该字段的更新将为第二个字段留下或返回“空”。
Allow Zero Length = Yes
Default Value = ""
Required = Yes