我有一张表'foo'看起来像
ID | NAME
------+----------------------------
123 | PiratesAreCool
254 | NinjasAreCoolerThanPirates
和第二个表'bar'
SID | ID | created | dropped
------+------+------------+-----------
9871 | 123 | 03.24.2009 | 03.26.2009
9872 | 123 | 04.02.2009 |
bar.ID
是foo.ID
的引用(外键)。
现在我想防止当有一个具有相同ID和bar的记录时,你可以将新记录插入'bar'。在该记录上,dropped为null。
所以,当'bar'看起来如上所述
INSERT INTO BAR VALUES ('9873','123','07.24.2009',NULL);
应该被禁止,但是
INSERT INTO BAR VALUES ('9873','254','07.24.2009',NULL);
应该允许(因为'NinjasAreCoolerThanPirates'没有'打开'条记录。)
我该怎么做? 我希望我的问题很明确,有人可以帮助我。
答案 0 :(得分:3)
create unique index ix_open_bar on bar (id, dropped);
当然,这也会导致你不能每天两次掉落一次吧(除非掉落的是一个可以降低风险的时间戳)
实际上,我注意到Postgres支持部分索引:
create unique index ix_open_bar on bar (id) where dropped is null;
<强>更新强> 经过一些测试后,不会对空值强制执行唯一约束,但部分索引仍然有效。
如果您不想使用部分索引,这可能也有效:
create unique index ix_open_bar on bar(id, coalesce(dropped, 'NULL'));
但是,在使用coalesce时,您需要在它们上使用相同的数据类型(因此,如果drop是时间戳,则需要将'NULL'更改为时间戳值)。
答案 1 :(得分:3)
如果您的ID
栏中没有“打开”记录,则只会插入记录INSERT INTO bar
SELECT '9873','254','07.24.2009',NULL
WHERE NOT EXISTS(SELECT 1 FROM bar WHERE ID='254' AND dropped IS NULL)
答案 2 :(得分:2)
在insert bar
上设置一个触发器,用于检查当前行的ID是否已存在于表中,如果是,则拒绝它。
我不知道具体的postgres语法,但它应该是这样的:
CREATE TRIGGER trigger_name BEFORE INSERT ON bar
IF EXISTS (
SELECT 1
FROM bar
WHERE bar.ID = inserted.ID
AND bar.dropped IS NULL
)
BEGIN
// raise an error or reject or whatever Postgres calls it.
END
然后,每当您尝试插入bar
时,此触发器将检查是否已存在某些内容,如果存在则拒绝它。如果bar.dropped
不为null,则允许插入正常。
如果有人知道正确的语法,请随时编辑我的答案。
答案 3 :(得分:2)
您可以使用WHERE子句创建部分索引。为此您可以这样做;
CREATE UNIQUE INDEX my_check on bar(id) where dropped is null;
假设表中不存在id 124,则允许这样做,但对于给定的ID,只有一条记录可以丢弃= NULL:
INSERT INTO BAR VALUES ('9873','124','07.24.2009',NULL);
这将被允许或不存在已经存在
INSERT INTO BAR VALUES ('9873','124','07.24.2009','07.24.2009');
如果已经存在125,则不允许这样做
INSERT INTO BAR VALUES ('9873','125','07.24.2009',NULL);
但这会
INSERT INTO BAR VALUES ('9873','125','07.24.2009','07.24.2009');