SQL / Oracle:是否可以在检查约束中使用组函数?

时间:2017-12-02 11:03:28

标签: sql oracle constraints

我的表格是:

 CREATE TABLE member
             (
                          svn      INTEGER,
                          campid   INTEGER,
                          tentname VARCHAR(4),
                          CONSTRAINT member_fk_svn FOREIGN KEY (svn) REFERENCES people,
                          CONSTRAINT member_fk_campid FOREIGN KEY (campid) REFERENCES camp ON
             DELETE CASCADE,
                    CONSTRAINT member_pk PRIMARY KEY (svn, campid),
                    CONSTRAINT member_fk_tentname FOREIGN KEY (tentname) REFERENCES tent,
                    CONSTRAINT check_teilnehmer_zelt CHECK (Count(zeltname) over (PARTITION BY (zeltname
             AND    lagerid)) )<= zelt.schlafplaetze
             ); 

使用最后一个约束,我想检查分配给帐篷的成员数量多于其容量。

感谢你的帮助

2 个答案:

答案 0 :(得分:2)

不,不是。来自文档:

  

如果应用于搜索条件,则必须始终返回相同的值   相同的价值观。因此,它不能包含以下任何内容:

* Dynamic parameters (?)
* Date/Time Functions (CURRENT_DATE, CURRENT_TIME, CURRENT_TIMESTAMP)
* Subqueries
* User Functions (such as USER, SESSION_USER, CURRENT_USER)

答案 1 :(得分:2)

这需要SQL 断言,Oracle目前(或任何DBMS)目前都不支持。但是,Oracle是considering adding support for these in the future(请提出这个想法!)

使用物化视图的解决方案

目前,您可以使用带有检查约束的物化视图(MV)来实现此约束 - I blogged about many years ago。在您的情况下,物化视图查询将类似于:

select t.tent_id
  from tents t, members m
 where m.tent_id = t.tent_id
 group by t.tent_id
 having sum(m.num_members) > t.capacity;

检查约束可以是:

check (t.tent_id is null)

对于物化视图返回的任何行,将违反检查约束,因此确保MV始终为空,即不存在容量超过的帐篷。

注意:

  1. 我故意不使用ANSI连接语法,因为MV不​​喜欢它(旧语法允许相同的连接,但ANSI语法不允许)。当然可以先尝试ANSI。
  2. 我还没有确认在具有REFRESH COMPLETE ON COMMIT的MV中允许此特定查询。关于什么可以使用和不可以使用的规则因Oracle的版本而异。
  3. 注意维护MV的性能影响。
  4. 使用触发器的替代解决方案

    另一种方法是将一个列total_members添加到tents表,并使用members上的触发器来维持这一点。

    create trigger members_trg
      after insert or delete or update of num_members on members
      for each row
      declare
        l_total_members tents.total_members%type;
      begin
        select total_members
          into l_total_members
          from tents
         where tent_id = nvl(:new.tent_id,:old.tent_id)
           for update of total_members;
    
        if inserting then
          l_total_members := l_total_members + :new.num_members;
        elsif deleting then
          l_total_members := l_total_members - :old.num_members;
        elsif updating then
          l_total_members := l_total_members - :old.num_members + :new.num_members;
        end if;
    
        update tents
           set total_members = l_total_members 
         where tent_id = nvl(:new.tent_id,:old.tent_id);
      end;
    

    然后只需添加检查约束:

    alter table tents add constraint tents_chk
      check (total_members <= capacity);
    

    通过维护tents表中的总数,此解决方案可以序列化事务,从而避免在多用户环境中使用其他基于触发器的解决方案时数据损坏。