【问题标题】:Trigger to check for duplicates触发器检查重复项
【发布时间】:2012-01-18 21:51:00
【问题描述】:

我正在编写一个触发器,但我遇到了一些问题。触发器执行和编译没有错误,但由于某些原因它不能完成我想要的工作。如果有人可以帮助我。

问题来了:

编写一个在插入、更新属性时执行的触发器。输入的每个属性都会与具有相同属性的其他属性进行检查:代理、所有者、地址,如果找到,则将属性状态更新为“双重”作为重复项。

我正在插入相同的数据,它允许我这样做,但通常不会!

这是我的桌子:

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;

谢谢。

【问题讨论】:

  • 声明唯一索引不是更容易吗?
  • 主键或唯一约束有什么问题?另外两张表的用途是什么?作业?
  • 听起来这是一道作业题。如果上述所有都相同或只有其中一个相同,您是否应该防止重复?
  • 是的,这是一项家庭作业,就在我插入新数据时,例如,如果它具有相同的地址或所有者,则不应允许插入数据。
  • 告诉你的老师触发器是个坏主意。当然,如果数据模型可以受到约束。

标签: sql database oracle triggers


【解决方案1】:

通常,您不能在触发器中强制执行这种约束。您需要使用约束。

如果您尝试使用触发器,您将面临的问题是您通常会遇到“变异表”异常。通常,表 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'

【讨论】:

  • 首先感谢您的解释,是的,我现在遇到了突变问题。当我尝试插入新数据时,它说: ORA-04091:表 YLLKA.PROPERTIES 正在变异,触发器/函数可能看不到它 ORA-06512:在“YLLKA.CHECK_DUPLICATE”,第 4 行 ORA-04088:执行期间出错触发器“YLLKA.CHECK_DUPLICATE”ORA-06512:在“YLLKA.DATES”第 4 行 ORA-04088:执行触发器“YLLKA.DATES”时出错
  • @Illyricum N. - 是的,这是意料之中的。正如我所说,您可以使用多个触发器、一个包和一个集合(或在 11g 中使用复合触发器)来解决变异触发器异常,但这会显着增加解决方案的复杂性。由于约束是实现这一点的正确方法,我会非常犹豫是否在定义这些多个触发器的路径上走得太远。
  • 我也不会理解。但我怎样才能使这项工作?尽管我开始喜欢触发器,但我对此感到厌倦,但它们会引起很多问题并使您感到紧张。
  • 贾斯汀,我让它工作我刚刚禁用了我创建的另一个触发器,因为我正在使用 toad。非常感谢您的解释。这对我帮助很大。如果您不介意,我还有一个简短的问题?
  • @Illyricum N. - 请注意,如果您在桌子上执行INSERT ... SELECT 而不是INSERT ... VALUES,您将立即获得变异触发器异常,在这种情况下您需要三个触发解决方案,或者您需要通过约束正确执行此操作。而且您仍然存在触发器无法处理多用户系统的问题。
【解决方案2】:

作业说如果重复,则将状态更改为加倍,而不是阻止它

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;

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2013-04-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-03-14
    • 2020-01-03
    相关资源
    最近更新 更多