如何添加约束来检查Oracle SQL中的总和?

时间:2019-03-26 23:08:10

标签: sql oracle plsql

我目前正在做一个学校项目,我们需要在其中创建房地产管理公司的数据库。我们有一个OWNER表,一个BUILDING表和一个OWNERSHIP表。

我想确保当我输入所有权权益百分比的值时,来自不同所有者的所有所有权权益之和不超过100%。目前我还不知道该怎么做。

CREATE TABLE Building (
    buildingID          NUMBER (10) NOT NULL PRIMARY KEY,
    qtyUnits            NUMBER (3) NOT NULL,
    landValue           NUMBER (15) NOT NULL,
    purchasePrice       NUMBER (15) NOT NULL
);

CREATE TABLE Owners (
    ownerID          NUMBER (5) NOT NULL PRIMARY KEY,
    lastName         VARCHAR2 (50) NOT NULL,
    firstName        VARCHAR2 (50) NOT NULL,
    telephone        VARCHAR2(50) NOT NULL,
    email            VARCHAR2(10) NOT NULL
);

CREATE TABLE Ownership (
    ownerID             NUMBER (5) NOT NULL,
    buildingID          NUMBER (5) NOT NULL,
    ownershipStake      NUMBER (5,2) NOT NULL,
    CONSTRAINT PK_Ownership PRIMARY KEY (ownerID,buildingID)
);

4 个答案:

答案 0 :(得分:4)

所有与触发器相关的解决方案都有一个问题:只要系统中有多个用户,它们就不足以保证约束得到维持。例如,如果会话A插入51%的x,并且会话B插入51%的ownershipshare,则这两个插入都将成功,因为两个会话均未提交。然后,两个会话都提交,您的所有者总hpshare为102%。

解决这个问题的一种方法是使用带有约束的ownershipshare实例化视图。不幸的是,我认为实例化视图仅在Oracle Enterprise Edition中可用,而在Standard或Express中则不可用。我没有可供测试的EE实例,但是我认为这可以满足您的要求:

ON COMMIT

我做了一些额外的工作来使物化视图快速刷新,因此不必在每次提交时都重建整个东西,而只需在受影响的buildid上重新构建。

答案 1 :(得分:0)

编辑 :最初删除此内容是因为我意识到参与多个会话时还不够。取消删除以显示不显示“变异表”问题的解决方案的示例。您必须锁定表,以便一次只能有一个会话影响它。

您可以使用AFTER STATEMENT触发器进行此操作。整个语句完成后,该操作每insertupdatedelete运行一次。这有点草率,因为它可以验证表中的 all 行,甚至包括那些未受影响但出于您的目的可能已经足够的行。

create or replace trigger trig1 
after insert or update on ownership
declare
    l_count number;
begin
    select count(*) into l_count from (
      select buildingid, sum(ownershipstake)
        from ownership
      group by buildingid
      having sum(ownershipstake) > 100
    );

    if l_count > 0 then
        raise_application_error( -20001, 'Totals cant be over 100' );
    end if;
end;
/

insert into ownership values ( 1, 1, 99 );

insert into ownership values ( 2, 1, 2 );

Error starting at line : 24 in command -
insert into ownership values ( 2, 1, 2 )
Error report -
ORA-20001: Totals cant be over 100

正如我所说,这将验证整个表,即使我仅在此处插入了影响1座建筑物的行。因此,如果您有一百万座建筑物,它会不必要地验证999,999行,并且会对性能产生重大影响。

一种改进的方法是使用复合触发器,在before each row时间点,您将记录要更改的行的建筑物ID。然后,在after statement时间点,您将仅验证已修改的建筑标识。

答案 2 :(得分:0)

使用复合触发器

.category-ken4ward h5 {
   color: red;
 }

答案 3 :(得分:-1)

首先-您可以使用前端在单独的查询中进行管理(即,将最大赌注限制为剩余数量)。

您是否希望进行数据库检查-在“所有权”表上创建行级触发器会有所帮助。

已编辑:添加更多详细信息 因此,也许您已经发现触发器将遇到“变异表”,并且想知道“这家伙在说什么?” 好,让我解释一下:这不是问题的完整答案。

我首选的处理方式是结合使用行级AFTER触发器,表中的额外补充字段和检查约束。

  1. Ownership表中添加一个额外的字段,我们称之为owned_pct
  2. 在显示为owned_pct <= 100的字段上添加检查约束
  3. 创建行级AFTER触发器,该触发器将更新此值,例如对于INSERT:update Ownership set owned_pct= nvl(owned_pct,0)+:new.ownership_pct where building_id = :new.building_id;
  4. 请注意,对于INSERT / DELETE / UPDATE情况,更新查询会稍有不同,因此请确保对所有这些进行测试

此过程将尝试更新owned_pct列并导致违反约束,这将回滚事务,包括初始DML语句。