访问:复合唯一索引忽略 NULL

问题描述 投票:0回答:4

考虑这个表结构:

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 索引。

    • 裁员和不良做法。

我的同事正在考虑为每种可能的情况创建一个表:

  1. 不可为 null 的唯一
    Name
  2. 不可为 null 的唯一
    Name
    FK_TableB
  3. 不可为 null 的唯一
    Name
    FK_TableB
    FK_TableC

这是我唯一的解决方案吗?

database ms-access indexing database-design ms-access-2010
4个回答
1
投票

将 FK 字段设置为必填项,并向每个相关表插入默认/类似 NULL 的记录。

这将是我首选的解决方案,带有 FK

0

我不明白维护起来有多么痛苦 - 只需将记录插入相关表中一次,将 FK 默认值从 NULL 更改为 0,然后就可以了。

您可能需要更改一些应用程序逻辑(您现在测试

FK_TableB IS NOT NULL
,然后执行
FK_TableB > 0
)。

恕我直言,这也不是坏习惯,它比可为 null 的 FK 更好。

它可以让您免于进行大量的 OUTER JOIN - 它们可能会产生诸如不可编辑的查询结果或性能不佳之类的问题。


0
投票
在许多 SQL 数据库中,索引会忽略 NULL,以避免三值逻辑产生的悖论。 结果是唯一索引没有完全按照您想要的方式限制数据。

这就是我所说的三值逻辑。 当测试 NULL

NULL 是否相等时,结果既不是 TRUE 也不是 FALSE,而是第三个逻辑值 UNKNOWN。 如果这看起来像一罐丑陋的蠕虫,那是因为它确实如此。 您在 FK 中采用 NULL

不仅无法为引用的链接提供值,而且还断言此实例中不存在可选关系。 这是一种合理的解释,但并不是索引构建者通常使用的解释。 顺便说一句,对于任何 SQL 数据库,您都会遇到完全相同的问题。

解决方案? 好吧,您可以将数据标准化为第六范式,这种形式在标准化讨论中经常被省略。 在 6NF 中,每个可为空列都会分解为两个表,其中一个包含可为空列,另一个不包含可为空列。 结果是每一列都可以标记为不可为空,而不会损失表达能力。

这将帮助您解决您所提到的问题,但这很可能会带来更多麻烦,而不是其价值。

有一个无需编码的解决方案。

0
投票
这是喷气发动机中的一个损坏的功能。索引定义中的“忽略空值”标志应该具有这种效果,在我看来这是一个失败。我没有检查的是,我的印象是它在旧版本的 DAO 中做了正确的事情。在我的职业生涯中,我曾多次以这种方式建立索引(姓名+重复数据删除),其中“重复数据删除”几乎总是空的。

索引不适用于 Null 值,但适用于 Empty ("") 值。 将第二个字段设置为“禁止空”和“允许空字符串”,作为解决方案,将“”设置为其默认值。

插入新记录时,第二个字段将设置为空,索引将按照预期插入或不插入。该字段的更新将为第二个字段留下或返回“空”。


0
投票

Allow Zero Length = Yes Default Value = "" Required = Yes

Access 只会让您添加一个空字符串
我个人不喜欢存储空字符串,但在这种情况下,它似乎是最优雅的解决方案。

© www.soinside.com 2019 - 2024. All rights reserved.