Oracle 创建触发器以检查冲突

Oracle 创建触发器以检查冲突,oracle,plsql,triggers,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

我的任务是检查在客户时间表上插入或更新团体健身课程时,是否与日期和时间冲突。谁能帮帮我吗。这些是我的桌子:

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;
你的触发器正在比较。插入新行时,表中没有旧行,因此该记录中的所有字段都为空;因此,你的比较不匹配。您不能将任何内容与null进行比较,但这是一个单独的讨论。插入时无法匹配您使用的条件。更新时,将更新行中字段的现有值与更新的新值进行比较;因此,您当前的意思是更新必须更改customer\t\u id和customer\u id。除此之外,customer\t\u id可能应该是主键,因此更改通常不是一个好主意

所以我认为你误解了旧的含义。看起来customer\t\u id引用是一个错误,您试图确保表中没有该customer的记录,但OLD并没有告诉您这一点,因为它只引用受语句影响的当前行,而不是表中的任何其他行

根据你在问题中所说的,我不认为这实际上是你的最终目标——我认为你不希望客户有两次相同的时间表

鉴于OLD不能满足您的需要,您可能会考虑查询该表以查看这样一行是否已经存在。但你不能轻易地在一个触发器中做到这一点;如果您一次插入或更新多行,那么您将得到一个变异表错误。很容易滥用触发器,试图让它们做一些它们不是为之设计的事情

强制唯一性的正常方法是使用或唯一的复合键,而不是触发器:

alter table customer_timetable
add constraint timetableconflict unique (customer_id, timetable_id);
这也将创建一个唯一的索引来备份它;您可以直接创建一个唯一的索引,但声明约束更显式。这不是一个很好的约束名称,但我刚刚复制了您将要调用的触发器

您可以阅读更多关于:

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

当子表和父表位于分布式数据库的不同节点上时强制引用完整性 强制实施无法使用约束定义的复杂业务或引用完整性规则
您所描述的内容不属于这些类别。

您还有多远?本网站的目的不是为您从头开始工作。如果:new.CUSTOMER\u t\u ID=:old.CUSTOMER\u t\u ID=:new.CUSTOMER\u ID=:old.CUSTOMER\u ID,则在更新每行的CUSTOMER\u时间表之前创建或替换触发器trig1,然后引发应用程序错误-20000,‘存在冲突’;如果结束;终止通常,这将通过一个唯一的约束来实现。真的需要扳机吗?