postgres:如何在特殊情况下阻止INSERT

时间:2009-07-24 14:27:00

标签: sql database postgresql

我有一张表'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.IDfoo.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'没有'打开'条记录。)

我该怎么做? 我希望我的问题很明确,有人可以帮助我。

4 个答案:

答案 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');