如何在 PostgreSQL 中为联合类型建模

Jon*_*oad 6 postgresql

我们有一个规则的一般概念,其中特定的实现细节存储在他们自己的表中。我们目前有以下架构:

Rule 
 * id 
 * name
 * ruleAId
 * ruleBId
 * ....
 * ruleNId
 * created 
 * updated

RuleA
 * id 
 * ...

RuleB
 * id 
 * ...

....

RuleC
 * id 
 * ...
Run Code Online (Sandbox Code Playgroud)

我们不喜欢的部分是每个特定规则实现都有一个可为空的列。

我们有两种可能的解决方案,但都有明显的缺点:

  1. 将关系移动到具体实现——DOS数据库

将规则 ID 存储在具体的实现表上,所以我们的模式变成:

RuleA
 * id 
 * ruleId
 * ...

Rule 
 * id 
 * name
 * created 
 * updated
Run Code Online (Sandbox Code Playgroud)

正如标题所暗示的那样,这意味着每次需要查找规则实现时都要进行 N 次查询。估计对性能不利。

  1. 放弃参照完整性 - Yolo 完整性

如果我们从 Rule 表中删除对参照完整性的需求,我们只需要一个列来存储特定的实现主键和一个枚举来告诉我们 id 用于哪个表,给我们:

Rule 
 * id 
 * name
 * implementationType 
 * implementationId
 * created 
 * updated


RuleA
 * id 

...
Run Code Online (Sandbox Code Playgroud)

理想情况下,我们可以使用具有参照完整性的选项二。如果 implementationId 不是 bigInt,它可以是 FK 或 RuleA 或 RuleB 或 ... RuleN。

这可以在应用程序本身中进行编码,但数据库让我们保持诚实是很好的。

我们正朝着选项二前进,但是如果人们认为我错过了一个更惯用的 SQL 解决方案,我很感兴趣吗?

添加示例架构:

CREATE SEQUENCE s_rulea_id;
CREATE TABLE rulea (id BIGINT PRIMARY KEY default nextval('s_rulea_id'));
CREATE SEQUENCE s_ruleb_id;
CREATE TABLE ruleb (id BIGINT PRIMARY KEY default nextval('s_ruleb_id'));
CREATE SEQUENCE s_rulec_id;
CREATE TABLE rulec (id BIGINT PRIMARY KEY default nextval('s_rulec_id'));
CREATE SEQUENCE s_rulen_id;
CREATE TABLE rulen (id BIGINT PRIMARY KEY default nextval('s_rulen_id'));

CREATE SEQUENCE s_rule_id;
CREATE TABLE rule (id BIGINT PRIMARY KEY default nextval('s_rule_id'),
                  name CHARACTER VARYING(128) NOT NULL,
                  ruleAid BIGINT DEFAULT NULL references rulea(id),
                  ruleBid BIGINT DEFAULT NULL references ruleb(id),
                  ruleCid BIGINT DEFAULT NULL references rulec(id),
                  ruleNid BIGINT DEFAULT NULL references rulen(id));

INSERT INTO ruleb (id) VALUES (nextval('s_ruleb_id')); 
INSERT INTO ruleb (id) VALUES (nextval('s_ruleb_id')); 
INSERT INTO ruleb (id) VALUES (nextval('s_ruleb_id')); 

INSERT INTO ruleb (id) VALUES (nextval('s_ruleb_id')); 
INSERT INTO ruleb (id) VALUES (nextval('s_ruleb_id')); 
INSERT INTO ruleb (id) VALUES (nextval('s_ruleb_id')); 

INSERT INTO rulec (id) VALUES (nextval('s_rulec_id')); 
INSERT INTO rulec (id) VALUES (nextval('s_rulec_id')); 
INSERT INTO rulec (id) VALUES (nextval('s_rulec_id')); 


INSERT INTO rule (name,ruleBid) VALUES ('B 1',1); 
INSERT INTO rule (name,ruleBid) VALUES ('B 2',2); 
INSERT INTO rule (name,ruleBid) VALUES ('B 4',3); 
INSERT INTO rule (name,ruleBid) VALUES ('B 4',4); 
INSERT INTO rule (name,ruleBid) VALUES ('B 5',5); 
INSERT INTO rule (name,ruleBid) VALUES ('B 6',6); 

INSERT INTO rule (name,ruleCid) VALUES ('c 1',1); 
INSERT INTO rule (name,ruleCid) VALUES ('C 2',2); 
INSERT INTO rule (name,ruleCid) VALUES ('C 3',3); 

select * from rule
Run Code Online (Sandbox Code Playgroud)