【问题标题】:MySQL Question - Unique Key Not functioning correctly, or am I misunderstanding?MySQL 问题 - 唯一键无法正常运行,还是我误解了?
【发布时间】:2010-09-30 14:20:13
【问题描述】:

我正在尝试创建一个关系,其中可能包含四个不同部分中的任何一个,但相同部分的任何集合都应该被视为唯一的。

示例: 一个任务必须有一个指定的公司,可以选择有一个指定的位置、工作组和程序。 分配可能没有没有位置的工作组。

假设我们有公司 A、B、C;位置 X、Y、Z;工作组 I、J、K 和程序 1、2、3。

所以有效的关系可以包括 A - X - 我 - 1 A - Z - 2 经过 C C - 3 B - Z - K

但无效的关系包括 A - K(没有位置的工作组) Y - K - 1(无公司)

所以,为了创建我的表,我已经创建了

companyID INT NOT NULL,
FOREIGN KEY companyKEY (companyID) REFERENCES company (companyID),
locationID INT,
FOREIGN KEY locationKEY (locationID) REFERENCES location (locationID),
workgroupID INT,
FOREIGN KEY workgroupKEY (workgroupID) REFERENCES workgroup (workgroupID),
programID INT,
FOREIGN KEY programKEY (programID) REFERENCES program (programID),
UNIQUE KEY companyLocationWorkgroupProgramKEY (companyID, locationID, workgroupID, programID)

我认为这将处理我的所有关系,如果有工作组(我认为我可以通过编程方式或使用触发器很高兴地完成),则除了分配有位置的必要性之外

但是,当我测试此架构时,它允许我输入以下内容...

INSERT INTO test VALUES (1, null, null, null), (1, null, null, null);

...毫无怨言。我猜 (1, null, null, null) 不等于自身,因为包含了空值。如果是这种情况,我有什么办法可以处理这种关系?

任何帮助将不胜感激!

【问题讨论】:

    标签: mysql nullable composite-key unique-key


    【解决方案1】:

    我看到这是在 2009 年提出的。但是,它经常被 MySQL 请求:例如 https://bugs.mysql.com/bug.php?id=8173https://bugs.mysql.com/bug.php?id=17825。人们可以点击影响我尝试获得 MySQL 的关注。

    从 MySQL 5.7 开始,我们现在可以使用以下解决方法:

    ALTER TABLE test 
    ADD generatedLocationID INT AS (ifNull(locationID, 0)) NOT NULL,
    ADD generatedWorkgroupID INT AS (ifNull(workgroupID, 0)) NOT NULL,
    ADD generatedProgramID INT AS (ifNull(programID, 0)) NOT NULL,
    ADD UNIQUE INDEX (companyID, generatedLocationID, generatedWorkgroupID, generatedProgramID);
    

    生成列是虚拟生成列,没有存储空间。当用户插入(或更新)时,唯一索引会导致生成的列的值动态生成,这是一个非常快速的操作。

    【讨论】:

      【解决方案2】:

      我能想到的在没有额外触发器/编程的情况下处理这个问题的唯一方法是在每个引用的表中都有一个“以上都不是”值,这样你的测试就会看起来像

      INSERT INTO test VALUES (1, NO_LOCATION, NO_WORKGROUP, NO_PROGRAM),
                              (1, NO_LOCATION, NO_WORKGROUP, NO_PROGRAM)
      

      NO_* 标识符是您的 ID 列的正确类型/长度。这将失败,正如您所期望的那样。

      【讨论】:

        【解决方案3】:

        我认为重要的是要注意,有一种正确的方法可以解释和处理 NULL 值,并且 OP 表现出的行为正是预期的。您可以无视这种行为,并且您可以以任何您想要的方式处理您的查询,而不会引起我的反对,但最好“接受”描述某种形式的最佳实践的答案,而不是非标准的个人偏好。

        或者如果您不同意共识的最佳实践,您可以不接受任何答案。

        让答案尽快被接受并不是一场竞赛。我认为,审议和协作也应该成为这个过程的一部分。

        【讨论】:

          【解决方案4】:

          在 MySQL NULL != NULL 或任何东西中。所以这就是 UNIQUE 不起作用的地方。您应该为空白使用另一个默认值,例如零

          【讨论】:

            【解决方案5】:

            这是一个功能(虽然也不是我所期望的)。

            This thread 建议将您的键设为主键以获得您期望的行为:

            这是一个特性 - NULL 值是 未定义的值,因此两个 NULL 值不一样。可以是一个 有点令人困惑,但在什么时候有意义 你考虑一下。

            唯一的索引确实可以确保 非 NULL 值是唯一的;你可以 指定您的列不接受 NULL 值。

            【讨论】:

            • 将列设置为“NOT NULL”会起作用,但也需要添加 Rob 等数据项,我建议允许数据库正确匹配列出的要求 - 如果 NULL 不是允许,您需要一个“NO FOO”值,该值是 FK 引用的 FOO 表中的有效条目。
            • 关于将索引设为主键:唯一的问题是您无法创建 AUTO_INCREMENT 列,除非它是主键的一部分。这就是我遇到的问题。
            • 使 NULL'able 列成为 PK 的一部分的另一个问题是它们变为 NOT NULL 并且您将 0 或空字符串作为默认值。
            猜你喜欢
            • 1970-01-01
            • 2012-04-15
            • 1970-01-01
            • 2011-04-17
            • 2011-09-16
            • 2013-06-23
            • 2020-11-04
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多