使用筛选行比较排除约束
exclude constraint with filtered row comparison
示例基于https://www.postgresql.org/docs/current/btree-gist.html
假设我有一个架构:
CREATE TABLE zoo (
cage INTEGER,
animal TEXT,
is_agressive BOOLEAN,
constraint no_different_animals_in_same_cage EXCLUDE USING gist (cage WITH =, animal WITH <>)
);
no_different_animals_in_same_cage
防止两只不同的动物在同一个笼子里。我想要的是仅当其中一只动物 is_aggressive IS TRUE
时才具有该约束。所以在 cage
中可以有一只带斑马的鹿,只要 none 的 is_aggressive
标志设置为 TRUE
.
我该怎么做?
如果您只是想防止攻击性和非攻击性动物生活在同一个笼子里,您可能想将 is_aggressive
添加到 EXCLUDE
约束并将其转换为受支持的类型通过 btree_gist
,例如int4
(1 = 真,0 = 假):
CREATE TABLE zoo (
cage INTEGER,
animal TEXT,
is_aggressive BOOLEAN,
CONSTRAINT no_different_animals_in_same_cage
EXCLUDE USING gist (cage WITH =, animal WITH <>, int4(is_aggressive) WITH <>)
);
这会起作用:
INSERT INTO zoo VALUES(1,'zebra',false);
INSERT INTO zoo VALUES(1,'zebra',false);
INSERT INTO zoo VALUES(1,'deer',false);
INSERT INTO zoo VALUES(2,'lion',true);
INSERT INTO zoo VALUES(2,'lion',true);
这会失败:
INSERT INTO zoo VALUES(1,'lion',true);
ERROR: conflicting key value violates exclusion constraint "no_different_animals_in_same_cage"
DETAIL: Key (cage, animal, int4(is_aggressive))=(1, lion, 1) conflicts with existing key (cage, animal, int4(is_aggressive))=(1, zebra, 0).
SQL state: 23P01
请注意,仍然可以将两只具有攻击性的动物放入同一个笼子!为了防止它,您可以将 UNIQUE INDEX
添加到 table,这样在 EXCLUDE
约束之上它会检查传入的记录,看看是否有攻击性动物已经生活在特定的环境中笼子:
CREATE UNIQUE INDEX aggressive_animals_live_alone
ON zoo (cage,is_aggressive) WHERE (is_aggressive);
现在这也会失败:
INSERT INTO zoo VALUES(2,'lion',true);
INSERT INTO zoo VALUES(2,'killer bunny',true);
ERROR: duplicate key value violates unique constraint "aggressive_animals_live_alone"
DETAIL: Key (cage, is_aggressive)=(2, t) already exists.
如果你想执行更复杂的检查,我建议你看看触发器。
演示:db<>fiddle
正如@Arkaduisz Noster 在评论中指出的那样,如果允许至少一只攻击性动物与非攻击性动物共用一个笼子,则可以在 [=24] 中添加一个 WHERE
子句=]:
CREATE TABLE zoo (
cage INTEGER,
animal TEXT,
is_aggressive BOOLEAN,
CONSTRAINT no_different_animals_in_same_cage
EXCLUDE USING gist (cage WITH =, animal WITH <>) WHERE (is_aggressive)
);
演示:db<>fiddle
示例基于https://www.postgresql.org/docs/current/btree-gist.html
假设我有一个架构:
CREATE TABLE zoo (
cage INTEGER,
animal TEXT,
is_agressive BOOLEAN,
constraint no_different_animals_in_same_cage EXCLUDE USING gist (cage WITH =, animal WITH <>)
);
no_different_animals_in_same_cage
防止两只不同的动物在同一个笼子里。我想要的是仅当其中一只动物 is_aggressive IS TRUE
时才具有该约束。所以在 cage
中可以有一只带斑马的鹿,只要 none 的 is_aggressive
标志设置为 TRUE
.
我该怎么做?
如果您只是想防止攻击性和非攻击性动物生活在同一个笼子里,您可能想将 is_aggressive
添加到 EXCLUDE
约束并将其转换为受支持的类型通过 btree_gist
,例如int4
(1 = 真,0 = 假):
CREATE TABLE zoo (
cage INTEGER,
animal TEXT,
is_aggressive BOOLEAN,
CONSTRAINT no_different_animals_in_same_cage
EXCLUDE USING gist (cage WITH =, animal WITH <>, int4(is_aggressive) WITH <>)
);
这会起作用:
INSERT INTO zoo VALUES(1,'zebra',false);
INSERT INTO zoo VALUES(1,'zebra',false);
INSERT INTO zoo VALUES(1,'deer',false);
INSERT INTO zoo VALUES(2,'lion',true);
INSERT INTO zoo VALUES(2,'lion',true);
这会失败:
INSERT INTO zoo VALUES(1,'lion',true);
ERROR: conflicting key value violates exclusion constraint "no_different_animals_in_same_cage"
DETAIL: Key (cage, animal, int4(is_aggressive))=(1, lion, 1) conflicts with existing key (cage, animal, int4(is_aggressive))=(1, zebra, 0).
SQL state: 23P01
请注意,仍然可以将两只具有攻击性的动物放入同一个笼子!为了防止它,您可以将 UNIQUE INDEX
添加到 table,这样在 EXCLUDE
约束之上它会检查传入的记录,看看是否有攻击性动物已经生活在特定的环境中笼子:
CREATE UNIQUE INDEX aggressive_animals_live_alone
ON zoo (cage,is_aggressive) WHERE (is_aggressive);
现在这也会失败:
INSERT INTO zoo VALUES(2,'lion',true);
INSERT INTO zoo VALUES(2,'killer bunny',true);
ERROR: duplicate key value violates unique constraint "aggressive_animals_live_alone"
DETAIL: Key (cage, is_aggressive)=(2, t) already exists.
如果你想执行更复杂的检查,我建议你看看触发器。
演示:db<>fiddle
正如@Arkaduisz Noster 在评论中指出的那样,如果允许至少一只攻击性动物与非攻击性动物共用一个笼子,则可以在 [=24] 中添加一个 WHERE
子句=]:
CREATE TABLE zoo (
cage INTEGER,
animal TEXT,
is_aggressive BOOLEAN,
CONSTRAINT no_different_animals_in_same_cage
EXCLUDE USING gist (cage WITH =, animal WITH <>) WHERE (is_aggressive)
);
演示:db<>fiddle