我正在写一个触发器,我有一些问题。触发器执行并编译没有错误但由于某些原因它不能完成我想要的工作。如果有人可以帮助我。
以下是问题:
写入要在插入,更新PROPERTY时执行的触发器。输入的每个属性都会针对具有相同属性的其他属性进行检查:代理,所有者,地址,如果找到,则将属性状态更新为“双重”作为副本。
我正在插入相同的数据而且我允许这样做,但通常不会!
以下是我的表格:
create table Properties(
idProperties number(10) NOT NULL,
Type varchar2(45) NOT NULL,
SquareMeters varchar2(10) NOT NULL,
Rooms number(10) NOT NULL,
ConstructionDate date NOT NULL,
FloorLocation varchar(20),
Price number(10) NOT NULL,
CityView varchar2(20),
DateOfInsert date NOT NULL,
DateOfExiration date NOT NULL,
Address_FK number(20),
Service_FK number(20),
Ownership_FK number(20),
Status_FK number(20),
PropertyService_FK number(20))
create table Address(
idAddress number(10) NOT NULL,
address_name varchar2(20),
City_FK number(20))
create table OwnerAgent(
idOwnerAgent number(10) NOT NULL,
Name varchar2(50) NOT NULL,
LastName varchar2(50) NOT NULL,
PhoneNr number(20),
Email varchar2(20),
Sex varchar2(10),
Profesion varchar2(20),
Birthdate date,
LastLogInDate date NOT NULL,
Status varchar2(20),
Address_FK number(20))
create table Ownership(
idOwnership number(10) NOT NULL,
PercentageOwed number(10)NOT NULL,
RequiredPercentage number(10) NOT NULL,
OwnerAgent_FK number(20))
这是我的触发器:
CREATE OR REPLACE TRIGGER Check_Duplicate
before insert or update on properties
FOR each ROW
declare
v_dup number;
begin
select count(idProperties) INTO v_dup from properties where Address_FK=:NEW.Address_FK and
Ownership_FK=:NEW.Ownership_FK;
if v_dup > 0 then
Raise_Application_Error (-20100, 'This property already exists. The insert is cancelled.');
end if;
end;
谢谢。
答案 0 :(得分:5)
通常,您不能在触发器中强制执行此类约束。您需要使用约束。
如果您尝试使用触发器,您将遇到的问题是您通常会遇到“变异表”异常。通常,表A上的行级触发器(即properties
)无法查询表A.您可以通过创建包,在该包中创建集合,在before语句触发器中初始化集合来解决该问题,在行级触发器中将插入或更新的键写入集合,然后在after语句触发器中迭代集合的元素,并针对表发出适当的DML。然而,这涉及大量的移动部件和大量的复杂性(尽管如果你使用11g并且可以使用复合触发器,复杂性会降低)。
此外,如果您尝试使用触发器,则会在多用户环境中遇到问题。如果用户A在一个会话中插入一行,并且用户B在用户A提交之前在不同的会话中插入重复的行,则会话的触发器都不会检测到重复的行。您可以通过显式锁定父表中的行来解决此类问题,以便将插入序列化到表中(故意使应用程序更慢且可伸缩性更低)。但约束将是一种更有效和实用的解决方案。
尽管如此,如果您只使用INSERT ... VALUES
语法进行单行插入并将自己限制在一个会话中,那么您的触发器似乎可以正常工作
SQL> ed
Wrote file afiedt.buf
1 create table Properties(
2 idProperties number(10) NOT NULL,
3 Address_FK number(20),
4 Ownership_FK number(20)
5* )
SQL> /
Table created.
SQL> CREATE OR REPLACE TRIGGER Check_Duplicate
2 before insert or update on properties
3 FOR each ROW
4
5 declare
6 v_dup number;
7
8 begin
9 select count(idProperties) INTO v_dup from properties where Address_FK=
:NEW.Address_FK and
10 Ownership_FK=:NEW.Ownership_FK;
11
12 if v_dup > 0 then
13 Raise_Application_Error (-20100, 'This property already exists. The inse
rt is cancelled.');
14 end if;
15 end;
16 /
Trigger created.
SQL> insert into properties values( 1, 10, 100 );
1 row created.
SQL> insert into properties values( 2, 10, 100 );
insert into properties values( 2, 10, 100 )
*
ERROR at line 1:
ORA-20100: This property already exists. The insert is cancelled.
ORA-06512: at "SCOTT.CHECK_DUPLICATE", line 9
ORA-04088: error during execution of trigger 'SCOTT.CHECK_DUPLICATE'
答案 1 :(得分:1)
分配表示如果重复则将状态更改为double,而不是阻止它
CREATE OR REPLACE TRIGGER Check_Duplicate
before insert or update on properties
FOR each ROW
declare
v_dup number;
begin
select count(idProperties) INTO v_dup from properties where Address_FK=:NEW.Address_FK and
Ownership_FK=:NEW.Ownership_FK;
if v_dup > 0 then
:New.Status :='DOUBLE'
end if;
end;