稳定的三角关系?

Mar*_*aun 5 database-design sql-server sql-server-2012

我有一个代表特定类型操作的表格。让我们称之为[ACTION]

一个操作可以由用户 ( [USER]) 执行,所以我有关系[USER] 1:N [ACTION]

用户可以有孩子 ( [CHILD]),所以[USER] 1:N [CHILD].

问题开始于操作必须由用户执行的事实,但是它可以用户或其子代之一执行。

如果每个用户总是有一个或多个孩子,我可以简单地做[CHILD] 1:N [ACTION]而不是[USER] 1:N [ACTION],因为在孩子身上我会找到执行操作的用户。

如果我只是 add [CHILD] 0...1:N [ACTION],那么 child 成为 action 表中的一个可选字段,可能会添加一个不属于添加到 action 的用户的 child。

问题

  1. 这种情况通常称为什么?

  2. 如何克服这个问题或者我能走的最好的方法是什么?

我不想在代码中检查这个,仅数据库(SQL Server 2012)解决方案将是完美的。

例子

行动是一种投资。用户将始终接受投资,但他/她可以决定他/她是为他/她还是为他/她的孩子之一投资。在这种情况下,孩子总是未成年。如果孩子足够大,可以自己进行投资,那么它将注册并成为用户。所以这就是为什么孩子不能成为用户的原因。他们需要保持两个不同的实体。

所以我有点需要两个彼此保持稳定的关系。我需要知道(用户)采取了行动(投资),我需要知道为谁(用户或他/她的孩子之一)采取了行动(投资)。

我正在寻求一种解决方案,即不能与用户无关的孩子采取行动(投资)。换句话说,父亲/母亲只能为他/她或他/她的孩子投资,不能为别人的孩子投资。

ype*_*eᵀᴹ 5

我看到 2 个选项来实现这一点。第一个是你已经拥有的,稍作调整,以强制执行这部分:

我正在寻求一种解决方案,即不能为与用户无关的孩子采取行动(投资)。换句话说,父亲/母亲只能为他/她或他/她的孩子投资,不能为别人的孩子投资。

调整将是action references (child)在外键上有一个复合键。可以action (child_id)为空,但当值不为空时,外键约束确保它引用执行操作的用户的子项。

示例代码:

-- design 1
CREATE TABLE user
( user_id INT NOT NULL PRIMARY KEY 
) ;

CREATE TABLE child
( user_id  INT NOT NULL,
  child_id INT NOT NULL PRIMARY KEY,
  FOREIGN KEY (user_id)
    REFERENCES user (user_id),
  UNIQUE (user_id, child_id)      -- this is needed for the FK below 
) ;


CREATE TABLE action
( action_id INT NOT NULL PRIMARY KEY,
  user_id   INT NOT NULL,
  child_id  INT NULL,                  -- nullable
  FOREIGN KEY (user_id)
    REFERENCES user (user_id),
  FOREIGN KEY (user_id, child_id)
    REFERENCES child (user_id, child_id)
) ;
Run Code Online (Sandbox Code Playgroud)

另一种方法是将child表重命名为dependent / investor / beneficiary(选择一个更合适的名称)并不仅在那里存储孩子,还存储用户本身(因此所有投资者/受益人/用户的受抚养人)。这样只有一个,外键 from actiontoinvestor将需要,并且该列不可为空:

-- design 2
CREATE TABLE user
( user_id INT NOT NULL PRIMARY KEY 
) ;

CREATE TABLE investor
( user_id     INT NOT NULL,
  investor_id INT NOT NULL PRIMARY KEY,
  FOREIGN KEY (user_id)
    REFERENCES user (user_id),
  UNIQUE (user_id, child_id)      
) ;

CREATE TABLE action
( action_id   INT NOT NULL PRIMARY KEY,
  user_id     INT NOT NULL,
  investor_id INT NOT NULL,
  FOREIGN KEY (user_id, investor_id)
    REFERENCES investor (user_id, investor_id)
) ;
Run Code Online (Sandbox Code Playgroud)

child在第一个设计中拥有的表格可以是一个视图:

CREATE VIEW child AS
  SELECT user_id,
         investor_id AS child_id
  FROM investor
  WHERE user_id <> investor_id ;
Run Code Online (Sandbox Code Playgroud)

作为一个副作用,具有设计2,我们并不真正需要user_idaction表(除非其他,而不是在问题或性能方面的原因提到)。我们可以删除它并摆脱复合外键。该user_id可与发现加盟investor

-- design 2b
CREATE TABLE user
-- unchanged

CREATE TABLE investor
( user_id     INT NOT NULL,
  investor_id INT NOT NULL PRIMARY KEY,
  FOREIGN KEY (user_id)
    REFERENCES user (user_id)   
) ;

CREATE TABLE action
( action_id   INT NOT NULL PRIMARY KEY,
  investor_id INT NOT NULL,
  FOREIGN KEY (investor_id)
    REFERENCES investor (investor_id)
) ;

CREATE VIEW child AS
-- unchanged
Run Code Online (Sandbox Code Playgroud)

另一种更复杂但从以前的设计中汲取优点并捕获所有不同实体(人、用户、孩子、动作)的方法是使用超类型/子类型模式。

这基本上将以下内容添加到设计(实体person)中:

  • Aperson是 auser或 a child
    (具有子类型的超类型)

  • Aperson可以有任意数量的children.
    Achild正好有一个父级 ( user)。
    (1:n 关系)

  • Aperson可以是任意数量action(投资)的受益人。
    Anaction仅适用于一位受益人​​ ( person)。
    (1:n 关系)

代码:

-- design 3
CREATE TABLE person
( person_id INT NOT NULL PRIMARY KEY 
) ;

CREATE TABLE user
( user_id INT NOT NULL PRIMARY KEY, 
  FOREIGN KEY (user_id)
    REFERENCES person (person_id),      
) ;

CREATE TABLE child
( user_id  INT NOT NULL,
  child_id INT NOT NULL PRIMARY KEY,
  FOREIGN KEY (child_id)
    REFERENCES person (person_id),     
  FOREIGN KEY (user_id)
    REFERENCES user (user_id) 
) ;

CREATE TABLE action
( action_id   INT NOT NULL PRIMARY KEY,
  beneficiary_id INT NOT NULL,
  FOREIGN KEY (beneficiary_id)
    REFERENCES person (person_id)
) ;
Run Code Online (Sandbox Code Playgroud)

我们不需要user_idaction表中,因为一个企业的用户action可以通过查看其它表中找到,它要么是受益人自己(如果beneficiary_id是在user表),否则将是用户(从user_id在相关child)。

  • 不,你不能。`FOREIGN KEY (user_id, child_id) REFERENCES child (user_id, child_id)` 确保 `action (user_id)` 与您孩子的 `user_id` 相同。 (4认同)
  • 关于“不可接受”的设计 2(或 2b):表的内部设计和结构不必对系统/应用程序的用户可见。如果用户只看到表/视图`user / action / child`,那么 - 据他们所知 - 用户和孩子是分开的。 (2认同)