考虑这个表结构:
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
这是我唯一的解决方案吗?
答案 0 :(得分:1)
创建所需的FK字段,并为每个相关表插入一个默认/类似NULL的记录。
这是我首选的解决方案,使用FK 0
。
我不知道维护是多么痛苦 - 只需将记录插入相关表中一次,将FK默认值从NULL更改为0,然后完成。
您可能需要更改一些应用程序逻辑(现在测试FK_TableB IS NOT NULL
,然后执行FK_TableB > 0
)。
它可以帮助您避免执行大量的OUTER JOIN - 它们可能会产生不可编辑的查询结果或性能不佳等问题。
答案 1 :(得分:0)
索引忽略了许多SQL数据库中的 NULL ,以便支持三值逻辑引起的悖论。结果是唯一索引不会以您希望的方式约束数据。
这就是我所说的三重逻辑。当 NULL 与 NULL 测试相等时,结果既不是 TRUE 也不是 FALSE ,而是第三个逻辑值的 UNKNOWN 即可。如果这看起来像一个丑陋的蠕虫,那是因为它是。
您在FK中使用 NULL 不仅无法为引用的链接提供值,而且还断言此实例中不存在可选关系。这是一个合理的解释,但它不是索引构建者通常使用的解释。顺便说一下,几乎任何SQL数据库都会遇到完全相同的问题。
解决方案?那么,您可以将数据规范化为第六范式,这种形式在规范化讨论中经常被忽略。在6NF中,每个可空列导致分解为两个表,其中一个表包含可空列,另一个表不包含。结果是每个列都可以被标记为不可为空,而不会损失表达能力。
这会让你解决你所说的问题,但它可能比它的价值更麻烦。
答案 2 :(得分:0)
有一个无需编码的解决方案。
这是 Jet 引擎中的一个损坏的功能。索引定义中的“忽略空值”标志应该具有这种效果,在我看来这是失败的。我没有检查过的是,我的印象是它在旧版本的 DAO 中做正确的事情。在我的职业生涯中,我曾多次以这种方式(姓名和姓氏 + 重复数据删除)进行索引,其中“重复数据删除”几乎总是空的。
索引不适用于值 Null,但适用于值 Empty ("")。 将第二个字段设置为 'Null forbidden' 和 'Empty string allowed',作为解决方案,将 "" 设置为其默认值。
插入新记录时,第二个字段将设置为 Empty,索引将按预期插入或不插入。字段的更新将留下或返回“空”给第二个字段。