绕过 UNIQUE w NULL 约束的可接受方法?

Acceptable way to get around a UNIQUE w NULL constraint?

我有一个table如下:

我想在 (connection_id, parent_container_id, name) 上添加一个 UNIQUE KEY。然而,parent_container_idconnection_id 是一个分离联合——记录必须有一个或另一个。因此,我想也许使用值 1 作为 'null' 值(即使用自动递增 ID 时的第一个条目)并在 container 中创建一个 BASE 条目table 用于 1 记录。

我想对其强制执行唯一性的示例数据:

这是一种糟糕的使用方法,还是这似乎是一种在此处强制执行唯一性约束的好方法?如果这不是一个好方法,什么可能是更好的方法?


更新:我当前的解决方案现在使用带有 md5 散列的生成(虚拟)列:

ALTER TABLE container ADD unique_hash2 CHAR(32) GENERATED ALWAYS AS 
(MD5(CONCAT(COALESCE(connection_id, '-1'), COALESCE(parent_container_id, '-1'), name))) VIRTUAL UNIQUE

有些事情最好在应用程序中完成。用它来执行。或者考虑在 SQL 所需代码周围使用存储过程包装器。

table 的 PRIMARY KEY 必须包含非 NULL 列。但是 UNIQUE 二级索引 可能 包含 NULL 列。

因此,这两列都不能成为PK。它们的组合也不行。

执行此类要求:

  • 两个唯一索引

  • 检查约束

Table定义:

CREATE TABLE tab(
   container_id          INT PRIMARY KEY AUTO_INCREMENT,
   connection_id         INT,
   parent_container_id   INT,
   name          VARCHAR(100),
   UNIQUE INDEX (connection_id, name),
   UNIQUE INDEX (parent_container_id, name),
   CHECK ((connection_id IS NULL AND parent_container_id IS NOT NULL)
           OR
          (connection_id IS NOT NULL AND parent_container_id IS NULL))
);

db<>fiddle demo

数据测试:

INSERT INTO tab(connection_id, parent_container_id, name)
VALUES (1, NULL, 'hello');

INSERT INTO tab(connection_id, parent_container_id, name)
VALUES (1, NULL, 'hello');
-- Duplicate entry '1-hello' for key 'tab.connection_id'


INSERT INTO tab(connection_id, parent_container_id, name)
VALUES (NULL, 10, 'goodbay');

INSERT INTO tab(connection_id, parent_container_id, name) 
VALUES (NULL, 10, 'goodbay');
-- Duplicate entry '10-goodbay' for key 'tab.parent_container_id'


INSERT INTO tab(connection_id, parent_container_id, name)
VALUES (NULL, NULL, 'a');
-- Check constraint 'tab_chk_1' is violated.

INSERT INTO tab(connection_id, parent_container_id, name)
VALUES (2, 2, 'a');
-- Check constraint 'tab_chk_1' is violated.

SQL92标准定义:

A unique constraint is satisfied if and only if no two rows in a table have the same non-null values in the unique columns. In addition, if the unique constraint was defined with PRIMARY KEY, then it requires that none of the values in the specified column or columns be the null value.

对于NULL,可以理解为未知。虽然我们现在不知道,但是未来它有很多的可能性,只是我们还不知道。当然很多人认为是bug

对于上面介绍的parent_containerconnection_id这两个字段,为什么不从业务的角度view,对于NULL,改为设置一个业务上认为不可能的值,从而避免MySQL unique key

的限制

关系解决方案

在该上下文中响应 relational-database 标签。 SQL 是 Codd 在他的 Relational Model 中定义的数据子语言,它在 1980 年代被确立为标准。因此 SQL 是关系型的;关系是 SQL.

  • 此答案中的所有项目都是关系型的,可以在 SQL 中轻松实现,我们已经拥有它们数十年了。

Is this a poor approach to use or does this seem like a good way to enforce the Unique-ness constraint here? If it's not a good way, what might be a better way?

是的,它很差,有两个方面。首先,您试图在一个文件中做太多事情。第二,它不是Relational,而且是干净的;在关系范式中这样做的合乎逻辑的方法:因此,您的预期添加是有问题的。

  • 这不是数据库设计问题,而是严格回答错在哪里,并附上解释。
  1. 容器
    container_id; nameparent_container_id 表示一个简单的 single-parent 层次结构。这是一个事实。

    • 由于你有多个数据树或层次结构,每个数据树或层次结构都有一个根,你需要一个带 container_id 0 的锚行,根是 children 的,并且通知构造 PathPathName 的递归函数何时停止。这是一个Anchor row,有什么意思,不是fiddle避免Null。
    • 需要 AK ( parent_container_id, name ) 来防止 parent_container_id 中的重复名称。那是一个谓词。不要加倍并尝试用它做更多,而是添加另一个谓词。
  2. 连接
    connection_id 是一个单独的离散事实。我认为它仅适用于根。所以这是一个从属事实,对于 [1] 是可选的。它的完整性由调用函数(与 Subtype 文档中相同)的约束来维护,该函数检查 parent 是根。

    • Null 是一个红色标志,表示未完成规范化,如果对数据进行规范化,则不会存储 Null。 (当然,结果集中允许空值。)

    • 另外,通常,由于 Null 是未知的,因此 Key (UNIQUE) 的概念是未知的,是歇斯底里的。这就是标准禁止它的原因。

  3. "联合类型"
    在Relational范式中,“联合类型”的概念已经完全破产。这是不了解 关系模型 或 SQL 的学者使用的一种方法,他们教授和推广未实现 [=] 的 1960 年代记录归档系统和数据库系统160=] 标准正确。由于那些数据库系统不支持 SQL(调用函数的约束),该方法是 可能的替代方法:parent 中的附加索引和child 中的附加外键。每个级别都很可怕。不要将其用作通用方法。

    • 请注意,附加索引在索引意义上是反常的(container_id 已经是唯一的;在唯一字段中添加一些内容并不会使其更加唯一),其唯一目的是允许 child 中的外键,然后检查某些条件(这里,parent 是根)。

    • 显然,如果您的“SQL”不是SQL,请使用伪装的“SQL”方法

  4. 分离
    要实现 OR 或 XOR 门(形式析取),请使用适当的 Subtype 集群(而不是重载您拥有的已经很差的文件)。

数据模型

此模型提供了 relational-database 解决方案,这意味着 SQL,因此可以调用函数的适当约束。

  • 它受损是因为“主键”不是键而是物理 RecordId,不具有逻辑键的属性。结果将在 child 表中注意到。

此模型提供了一种在 MySQL 中可行的解决方案。

  • 典型的 1960 年代 pre-Relational,pre-DBMS,物理记录归档系统,被学术界称为“关系”,

  • 使用附加索引和 FK 来替代 SQL 约束,用于未正确实现 SQL 的数据库

符号

  • 我所有的数据模型都在 IDEF1X 中呈现,从 1980 年代早期开始可用,这是 1993 年唯一的关系数据建模标准。

  • IDEF1X Introduction 是 Codd 的关系模型 或其建模方法的新手的必备读物。请注意,IDEF1X 模型是完整的,它们具有丰富的细节和精度,显示了 所有 所需的详细信息,而 home-grown 模型不知道标准的必要性,远远不够更少的定义。这意味着,符号需要被完全理解。