简体   繁体   English

如何向表添加“CHECK EXISTS”约束?

[英]How to add a 'CHECK EXISTS' constraint to a table?

I'm fairly new to SQL/PSQL, and am familiar so far with adding a constraint to a table that checks that there NOT EXISTS a certain condition.我是 SQL/PSQL 的新手,到目前为止我很熟悉向表中添加一个约束来检查是否存在特定条件。 This makes sense to me, as each time a new row is added, it can check whether that row breaks the condition, and continue if it doesn't.这对我来说很有意义,因为每次添加新行时,它都可以检查该行是否打破了条件,如果没有则继续。

But how would I add a constraint to a table to check that there EXISTS a row that satisfies a condition?但是我如何向表添加约束以检查是否存在满足条件的行? At the moment, when the first row is inserted (which doesn't satisfy the condition, but a later one may do) it fails as the condition is not met.目前,当插入第一行时(不满足条件,但后面可能会满足),它会因为不满足条件而失败。

How do I implement this correctly?我该如何正确实施?

I tried writing it exactly like a CHECK NOT EXISTS constraint, but without the NOT.我试着把它写得完全像 CHECK NOT EXISTS 约束,但没有 NOT。 This resulted in the above issue, and I understand why.这导致了上述问题,我明白为什么。

A basic idea of what I've tried so far, and is conceptually what I want to work:到目前为止我已经尝试过的基本想法,并且在概念上是我想要工作的:

CREATE OR REPLACE FUNCTION CheckSomeLargeAttendance()
RETURNS BOOLEAN AS $$
BEGIN
    RETURN(
      EXISTS(
      SELECT 1
      FROM event e
      WHERE e.attending > 100
      )
    );
END;
$$ language plpgsql;

ALTER TABLE event
ADD CONSTRAINT SomeLargeAttendance CHECK(
  CheckSomeLargeAttendance()
);

Ie I want to check that, when all data is added to the table, there is at least one event with an attendance of more than 100.即我想检查一下,当所有数据都添加到表中时,至少有一个事件的出席人数超过 100。

What you are doing is unsupported, and it will lead to trouble.你的所作所为是不受支持的,它会导致麻烦。 The documentation says: 文件说:

PostgreSQL does not support CHECK constraints that reference table data other than the new or updated row being checked. PostgreSQL 不支持引用除正在检查的新行或更新行之外的表数据的CHECK约束。 While a CHECK constraint that violates this rule may appear to work in simple tests, it cannot guarantee that the database will not reach a state in which the constraint condition is false (due to subsequent changes of the other row(s) involved).虽然违反此规则的 CHECK 约束在简单测试中可能看起来有效,但它不能保证数据库不会达到约束条件为假的 state(由于涉及的其他行的后续更改)。 This would cause a database dump and restore to fail.这将导致数据库转储和恢复失败。 The restore could fail even when the complete database state is consistent with the constraint, due to rows not being loaded in an order that will satisfy the constraint.即使完整的数据库 state 与约束一致,还原也可能失败,因为未按满足约束的顺序加载行。 If possible, use UNIQUE , EXCLUDE , or FOREIGN KEY constraints to express cross-row and cross-table restrictions.如果可能,请使用UNIQUEEXCLUDEFOREIGN KEY约束来表达跨行和跨表限制。

If you dig around in the mailing list archives, you will find reports of such failures, for example here and here .如果您在邮件列表档案中四处寻找,您会发现此类失败的报告,例如此处此处

You could have such a check with a statement level trigger (but don't add the trigger before you insert the first row):您可以使用语句级触发器进行此类检查(但在插入第一行之前不要添加触发器):

CREATE FUNCTION has_big_event() RETURNS trigger
   LANGUAGE plpgsql AS
$$BEGIN
   IF NOT EXISTS (SELECT FROM event WHERE attending > 100)
   THEN
      RAISE EXCEPTION 'the table does not contain a big enough event';
   END IF;

   RETURN NULL;
END;$$;

CREATE TRIGGER has_big_event BEFORE INSERT OR UPDATE ON event
   FOR EACH STATEMENT EXECUTE FUNCTION has_big_event();

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM