用于检查值是否在另一个表中不存在的 SQL 约束

one*_*ror 3 sql postgresql database-design constraints unique-constraint

在我的 PostgreSQL 9.4数据库中,我有一个包含唯一值fields列的表name

我正在创建一个fields_new具有类似结构(此处不重要)和一列的新表name。我需要一种方法来约束name要插入到fields_new不存在于fields.name.

例如,如果fields.name包含值'color''length',我需要防止fields_new.name包含'color''length'值。因此,换句话说,我需要提供name两个表中的列之间没有任何重复值。约束应该是双向的。

Erw*_*ter 5

仅对新条目强制执行约束 fields_new

CHECK约束应该是不可变的,这通常排除对其他表的任何类型的引用,这些表本质上是不可变的。

为了允许一些余地(尤其是时间函数),STABLE函数是可以容忍的。显然,这在具有并发写访问权限的数据库中是不完全可靠的。如果引用表中的行发生更改,则它们可能违反了约束。

通过使其NOT VALID(Postgres 9.1+)声明约束的无效性质。这样 Postgres 也不会尝试在恢复期间强制执行它(这可能会失败)。详情在这里:

该约束仅对新行强制执行。

CREATE OR REPLACE FUNCTION f_fields_name_free(_name text)
  RETURNS bool AS
$func$
SELECT NOT EXISTS (SELECT 1 FROM fields WHERE name = $1);
$func$  LANGUAGE sql STABLE;

ALTER TABLE fields_new ADD CONSTRAINT fields_new_name_not_in_fields
CHECK (f_fields_name_free(name)) NOT VALID;
Run Code Online (Sandbox Code Playgroud)

另外,当然, a UNIQUEorPRIMARY KEY约束fields_new(name)以及 on fields(name)

有关的:

双向执行

您可以更进一步,CHECK在第二个表上镜像上述约束。当两个事务同时写入两个表时,仍然不能保证防止令人讨厌的竞争条件。

或者您可以使用触发器手动维护“物化视图”:两name列的联合。在UNIQUE那里添加一个约束。不像单个表上的相同约束那样坚如磐石:同时写入两个表可能存在竞争条件。但可能发生的最坏情况是死锁迫使事务回滚。如果所有写入操作都级联到“物化视图”,则不会出现永久性违规。

类似于此相关答案中的“阴暗面”:

只是,你需要触发器INSERT/ UPDATE/DELETE这两个表。