创建触发器以检查冲突

时间:2015-11-12 23:17:10

标签: oracle plsql triggers

我的任务是检查在客户时间表上插入或更新团体健身课时与日期和时间没有冲突。有人可以帮帮我吗。这些是我得到的表格:

Name          Null     Type         
------------- -------- ------------ 
CUSTOMER_T_ID NOT NULL NUMBER(38)   
C_DATE        NOT NULL TIMESTAMP(6) 
TIMETABLE_ID  NOT NULL NUMBER(38)   
CUSTOMER_ID   NOT NULL NUMBER(38)   

Desc Timetable

Name              Null     Type         
----------------- -------- ------------ 
TIMETABLE_ID      NOT NULL NUMBER(38)   
CLASS_DAY         NOT NULL VARCHAR2(50) 
CLASS_LOCATION    NOT NULL VARCHAR2(50) 
CLASS_START_TIME  NOT NULL TIMESTAMP(6) 
CLASS_FINISH_TIME NOT NULL TIMESTAMP(6) 
WORKOUT_CLASS_ID  NOT NULL NUMBER(38)   
TRAINER_ID        NOT NULL NUMBER(38)   

Desc Workout_class

Name             Null     Type          
---------------- -------- ------------- 
WORKOUT_CLASS_ID NOT NULL NUMBER(38)    
NAME             NOT NULL VARCHAR2(20)  
WORKOUT_TYPE     NOT NULL VARCHAR2(200) 
EQUIPMENT_USED   NOT NULL VARCHAR2(200) 
RESULTS          NOT NULL VARCHAR2(200) 
COST             NOT NULL FLOAT(126)    
INTENSITY_LEVEL  NOT NULL VARCHAR2(50)  
CLASS_DURATION   NOT NULL NUMBER(38)    

Desc Customers

Name             Null     Type          
---------------- -------- ------------- 
CUSTOMER_ID      NOT NULL NUMBER(38)    
FIRST_NAME       NOT NULL VARCHAR2(50)  
LAST_NAME        NOT NULL VARCHAR2(50)  
AGE              NOT NULL NUMBER(38)    
ADDRESS          NOT NULL VARCHAR2(100) 
CITY             NOT NULL VARCHAR2(50)  
MOBILE_PHONE     NOT NULL NUMBER(10)    
EMAIL                     VARCHAR2(50)  
PICTURE                   BFILE()       
CUSTOMER_TYPE_ID NOT NULL NUMBER(5) 

触发器正在编译但是当我尝试将同一个客户插入相同的时间表时,他已经没有提出错误但是插入了行

create or replace trigger timetableconflict
  before insert or update on customer_timetable
  for each row
begin
  if :new.customer_T_ID = :old.Customer_T_ID and :new.Customer_ID = :old.Customer_ID
  then 
    raise_application_error(-20000,'customer cannot enrol into same class again');
  end if;
end;

1 个答案:

答案 0 :(得分:0)

您的触发器正在比较the OLD and NEW pseudorecords。插入新行时,表中没有OLD行,因此该记录中的所有字段都为空;因此你的比较不匹配。 (您无法将任何内容与null进行比较,但这是一个单独的讨论)。您使用的条件永远不会匹配插入。当您更新时,您正在比较要更新的行中字段的现有值,并使用新值进行更新;因此,您目前正在说更新必须更改customer_t_idcustomer_id。除了其他任何东西,看起来customer_t_id可能应该是主键,因此改变它通常不是一个好主意。

所以我认为你误解了OLD所代表的东西。看起来customer_t_id引用是错误的,并且您正在尝试确保表中没有客户记录 - 但是OLD并没有告诉您,因为它只引用当前受影响的行通过语句,而不是表中的任何其他行。

我认为这不是你在问题中所说的最终目标 - 我认为你不希望客户有两次相同的时间表。

鉴于OLD没有按照您的意愿执行操作,您可能会考虑查询表以查看此行是否已存在。但你不能(轻松地)在触发器中做到这一点;如果您一次插入或更新多行,则会出现变异表错误。通过尝试让他们做一些他们不是为自己设计的东西,很容易滥用触发器。

强制执行该唯一性的常规方法是使用unique constraint(或“唯一复合键”)而不是触发器:

alter table customer_timetable
add constraint timetableconflict unique (customer_id, timetable_id);

这也将创建一个独特的索引来支持它;您可以直接创建唯一索引,但声明约束更明确。 (这不是一个很好的约束名称,但我只是复制了你要称之为触发器的东西)。

您可以阅读有关how triggers and constraints differ的更多信息:

  

与强制执行相同规则的触发器相比,约束更容易编写并且更不容易出错。但是,触发器可以强制执行一些约束不能的复杂业务规则。 Oracle强烈建议您仅在以下情况下使用触发器来约束数据输入:

     
      
  • 在子表和父表位于分布式数据库的不同节点上时强制实施参照完整性
  •   
  • 强制执行无法使用约束定义的复杂业务或参照完整性规则
  •   

您所描述的内容不属于这些类别。