Sql,触发函数而不是简单约束

时间:2018-06-09 12:37:18

标签: sql postgresql

我正在攻读“数据库”课程,我们在老师上传的示例考试中进行了这项练习,遗憾的是他没有给出完整的修正,只是提示了一些。 我无法理解为什么在下面的例子中他告诉我们使用触发器函数而不是简单的NOT NULL约束。

This is the exercise

现在我会像这样实现B和C之间的关系:

CREATE TABLE B (
  b1 int PRIMARY KEY,
  b2 varchar(255)
);

CREATE TABLE C (
  c1 varchar(255) PRIMARY KEY,
  c2 int
);

CREATE TABLE BtoC (
 b1 int REFERENCES B(b1) ON DELETE RESTRICT ON UPDATE CASCADE,
 c1 varchar(255) NOT NULL REFERENCES C(c1) ON DELETE RESTRICT ON UPDATE CASCADE,  -- This would ensure the same constraint, that C has to be at least once in the relation table?
 PRIMARY KEY(b1,c1)
);

但他告诉我们表B和C之间的关系,我们需要一个触发函数来满足关系的基数,这是他的话:

“NOTHING上的NOT NULL不会产生任何影响(NOT NULL仅适用于现有行,而不适用于不存在的行),并且不能保证约束有效。因此,NOT NULL对于关系不起作用表,仅用于外键。“

我无法理解他的推理,也许有些人可以向我解释一下?我真的很感激。

1 个答案:

答案 0 :(得分:1)

您的版本保证BtoC中的任何记录都有有效C引用。 确保每个BtoCC中至少有一行。这里棘手的部分是" 1"在这段关系中。

这是一种棘手的关系代表 - 我甚至不知道在SQL中是否值得这样做。

一种方法是突出显示其中一个值。例如,如果数据是家庭中的人,则突出显示的人可能是家庭主管"。你需要其中一个。因此,您可以将其实现为:

CREATE TABLE C (
  c1 varchar(255) PRIMARY KEY,
  c2 int,
  b_special int not null references b(b1)
);

这在技术上解决了这个问题,但参考B值分为两个表而不是一个。

如果您希望特殊B位于BtoC,那么它会变得棘手。你可以用反向引用来做到这一点:

alter table c add constraint fk_c_b_special
    foreign key (b_special, c) references btoc(b1, c1);

然后您会发现插入数据变得棘手 - 两个表中都需要存在行才能将行插入到任一表中。

常见的解决方案可能是:

  • 放宽约束,让app插入两个表格。
  • 添加"特殊"列到C,但不要检查列实际上是否在BtoC中(尽管代码会一直插入它)。
  • 添加"特殊"列到C,然后允许其余列的0-n关系。
  • 为BtoC写一个删除触发器,它不允许删除给定C的最后一个B.