存储具有来自同一外部表的恰好 n 个外键的记录的替代方法,其中关系不能重复

gro*_*tar 6 normalization foreign-key database-theory

假设有实体称为singulars,实体称为relationships

singulars组成一个relationships实体正好需要两个。

单数不能relationships以任何顺序在中的其他地方重复。

建模它的一种方法可能是这样的:

+----------------+
|relationships   |         +----------+
+----------------+         |singulars |
|id              |         +----------+
|singular_id_1   <---------+id        |
|singular_id_2   <---+     |attribute1|
|pair_description|         |attribute2|
|pair_date       |         |          |
|                |         +----------+
+----------------+
Run Code Online (Sandbox Code Playgroud)

使用这种模式,有必要检查两个外键字段relationships是否存在singulars,它可能在任一侧。顺序无关紧要,但它是在模式中定义的......所以查询最终会得到许多AND/OR组和案例。

扩展这种方法可以为每对存储两条记录,并在singular_id_[n]两侧交换。虽然这解决了一些查询的复杂性,但它会引入额外的复杂性使其不可行。

使用中间表似乎是一种潜在的解决方案:

+----------------+       +-----------------------+
|relationships   |       |singulars_relationships|        +----------+
+----------------+       +-----------------------+        |singulars |
|id              <-------+relationship_id        |        +----------+
|pair_description|       |singular_id            +-------->id        |
|pair_date       |       |                       |        |attribute1|
|                |       +-----------------------+        |attribute2|
+----------------+                                        |          |
                                                          +----------+
Run Code Online (Sandbox Code Playgroud)

所以记录可能会变成这样:

+----------------------------------+
|relationships                     |
+----------------------------------+
|id   pair_description   pair_date |
+----------------------------------+
|1    Fizz buzz blitz    2022-02-20|
|2    Blitz buzz fizz    2022-02-22|
+----------------------------------+

+----------------------------------+
|singulars_relationships           |
+----------------------------------+
|relationship_id   singular_id     |
+----------------------------------+
|1                 1               |
|1                 2               |
|2                 3               |
|2                 4               |
+----------------------------------+

+-----------------------------+
|singulars                    |
+-----------------------------+
|id   attribute1   attribute2 |
+-----------------------------+
|1    Fizz         Blitz      |
|2    Buzz         Foo        |
|3    Bar          World      |
|4    Blorg        Hello      |
+-----------------------------+
Run Code Online (Sandbox Code Playgroud)

在那里,singulars_relationships是定义对的地方。如果 asingular_id存在于那里,则它已经是一对。这种模式可能出现的一个问题可能是三个或更多singular_ids 最终可能与 a 相关联relationship_id,然后“恰好 n”约束将受到损害。

这种情况有官方条款吗?以及其他理论和替代方案?

Dav*_*oft 9

这种情况有官方条款吗?

是的。这是一个对称关系。这里的“关系”与“关系数据库”中的含义相同。RDBMS 是一种围绕存储关系而设计的数据库管理系统。然而,RDBMS 没有存储对称关系的本机方式。您要么必须将两个元组,例如 (a,b) 和 (b,a) 存储为单独的行,要么必须使用某种约定来仅存储一个元组。一种常见的方法是对 FK 使用检查约束。

例如

check (singular_id_1 < singular_id_2)
Run Code Online (Sandbox Code Playgroud)

假设关系是反自反的


Len*_*art 7

渴望发表评论,所以我将其添加为大卫解决方案的补充。尽管该问题具有理论性质,但看看如何在现实生活中实施可能会很有趣。

在某些情况下,反自反属性和对称属性太强了,但我们仍然希望“唯一性”属性保持不变。一种常见的模式是使用BEFORE TRIGGERS使关系对称而不让用户知道对称属性:

CREATE TRIGGER trigger1
BEFORE INSERT ON t
REFERENCING NEW AS N
FOR EACH ROW
    SET (N.a, N.b) = (LEAST(N.a, N.b), GREATEST(N.a, N.b));
Run Code Online (Sandbox Code Playgroud)

表中的属性:

CHECK(a<=b);
UNIQUE(a,b);
Run Code Online (Sandbox Code Playgroud)

这个主题的一个变体是使用生成的列

CREATE TABLE t 
( a int not null
, b int not null
, least_a_b generated always as ( least(a,b) )
, greatest_a_b generated always as ( greatest(a,b))
, unique (least_a_b, greatest_a_b)
);
Run Code Online (Sandbox Code Playgroud)

生成的列也可能被隐藏:

least_a_b generated always as ( least(a,b) ) IMPLICITLY HIDDEN
Run Code Online (Sandbox Code Playgroud)

示例来自 Db2,但其他供应商应该存在类似的功能。