Oracle 满足条件时停止更新的SQL触发器

Oracle 满足条件时停止更新的SQL触发器,oracle,plsql,database-trigger,Oracle,Plsql,Database Trigger,我有3个表:项目、组件和供应商 我试图做的是编写一个触发器,如果组件和项目与供应商具有相同的城市,则不允许修改city的值 到目前为止,我所尝试的: create or replace TRIGGER Supplier_control BEFORE UPDATE of city ON Suppliers BEGIN DECLARE v_counter NUMBER := 0; SELECT COUNT(*) FROM (SELECT * FROM Suppliers s JOIN

我有3个表:项目、组件和供应商

我试图做的是编写一个触发器,如果组件和项目与供应商具有相同的城市,则不允许修改city的值

到目前为止,我所尝试的:

create or replace TRIGGER Supplier_control
BEFORE UPDATE of city
ON Suppliers
BEGIN
    DECLARE v_counter NUMBER := 0;
    SELECT COUNT(*) FROM (SELECT * FROM Suppliers s JOIN Projects p ON (s.city=p.city) JOIN Components c ON (c.city=s.city)) INTO v_counter;
    IF (v_counter != 0)
    THEN
        raise_application_error(-20111,'Can't change the city for this supplier!');
    END IF;
END;
尝试运行此操作后,出现以下错误:

Error at line 3: PLS-00103: Encountered the symbol "JOIN" when expecting one of the following:

   ) , with group having intersect minus order start union where
   connect
Error at line 3: PL/SQL: SQL Statement ignored
请注意,行号是指开始后的行号

在开始之前,我还尝试编写了declare部分,我得到了以下错误:

Error at line 3: PLS-00103: Encountered the symbol "JOIN" when expecting one of the following:

   ) , with group having intersect minus order start union where
   connect
Error at line 3: PL/SQL: SQL Statement ignored

为了消除这些错误,需要做些什么?

您正在尝试访问声明中指定为零的变量。 设置从查询结果中得到的变量将是一个数字

create or replace TRIGGER Supplier_control
BEFORE UPDATE of city
ON Suppliers
BEGIN
    DECLARE v_counter NUMBER := 0;
-- change this line
    SET v_counter = (SELECT COUNT(*) FROM (SELECT * FROM Suppliers s JOIN Projects p ON (s.city=p.city) JOIN Components c ON (c.city=s.city)));
    IF (v_counter != 0)
    THEN
        raise_application_error(-20111,'Can't change the city for this supplier!');
    END IF;
END;

将计数查询更改为已编辑的查询。首先,只需运行查询SELECT COUNT*FROM SELECT*FROM供应商的加入项目p ON s.city=p.city加入组件c ON c.city=s.city如果输出为数字,则分配给变量v_计数器

您试图访问的变量在声明中分配为零。 设置从查询结果中得到的变量将是一个数字

create or replace TRIGGER Supplier_control
BEFORE UPDATE of city
ON Suppliers
BEGIN
    DECLARE v_counter NUMBER := 0;
-- change this line
    SET v_counter = (SELECT COUNT(*) FROM (SELECT * FROM Suppliers s JOIN Projects p ON (s.city=p.city) JOIN Components c ON (c.city=s.city)));
    IF (v_counter != 0)
    THEN
        raise_application_error(-20111,'Can't change the city for this supplier!');
    END IF;
END;

将计数查询更改为已编辑的查询。首先简单地运行查询SELECT COUNT*FROM SELECT*FROM Suppliers s JOIN Projects p ON s.city=p.city JOIN Components c ON c.city=s.city如果输出为数字,则分配给变量v_counter

存在一些语法错误

DECLARE在BEGIN语句之前。 在SELECT之后进入,在FROM之前进入。 在raise_应用程序_error-20111中,“无法更改此供应商的城市!”;您无法写入“不能”,因为第一个单引号将以“不能”的引号结尾,从而导致字符串在此结尾。因此,您应该删除它或执行以下操作:提出_应用程序_错误-20111,“不能更改此供应商的城市!”; 综上所述,完整的代码应该如下所示:

CREATE OR REPLACE TRIGGER Supplier_control
BEFORE UPDATE of city
ON Suppliers
DECLARE
    v_counter NUMBER := 0;
BEGIN
    SELECT COUNT(*) 
    INTO v_counter
    FROM (SELECT * FROM Suppliers s JOIN Projects p ON s.city=p.city JOIN Components c ON c.city=s.city);

    IF v_counter != 0 THEN
        raise_application_error(-20111,'Can''t change the city for this supplier!');
    END IF;

END;

希望这有帮助。

有一些语法错误

DECLARE在BEGIN语句之前。 在SELECT之后进入,在FROM之前进入。 在raise_应用程序_error-20111中,“无法更改此供应商的城市!”;您无法写入“不能”,因为第一个单引号将以“不能”的引号结尾,从而导致字符串在此结尾。因此,您应该删除它或执行以下操作:提出_应用程序_错误-20111,“不能更改此供应商的城市!”; 综上所述,完整的代码应该如下所示:

CREATE OR REPLACE TRIGGER Supplier_control
BEFORE UPDATE of city
ON Suppliers
DECLARE
    v_counter NUMBER := 0;
BEGIN
    SELECT COUNT(*) 
    INTO v_counter
    FROM (SELECT * FROM Suppliers s JOIN Projects p ON s.city=p.city JOIN Components c ON c.city=s.city);

    IF v_counter != 0 THEN
        raise_application_error(-20111,'Can''t change the city for this supplier!');
    END IF;

END;
希望这能有所帮助。

通过上下匹配(包括大小写不敏感)检查一个城市是否匹配整个表项目的值

您不需要也不应该在select语句中使用Supplier表,因为表名可能发生变异错误:

CREATE OR REPLACE TRIGGER Supplier_control
BEFORE UPDATE of city
ON Suppliers
DECLARE 
    v_counter PLS_INTEGER;
BEGIN
    SELECT COUNT(*) 
      INTO v_counter
      FROM Projects p 
     WHERE lower(:new.city)=lower(p.city);

    IF (v_counter != 0) THEN
        raise_application_error(-20111,'Can''t change the city for this supplier!');
    END IF;
END;
如果v_计数器的初始化是冗余的,那么如果没有找到匹配的记录,它将已经为零。此外,请注意declare关键字的顺序,其中包括变量定义部分。

检查,按下限或上限匹配,包括大小写不敏感,城市是否匹配整个表项目的值

您不需要也不应该在select语句中使用Supplier表,因为表名可能发生变异错误:

CREATE OR REPLACE TRIGGER Supplier_control
BEFORE UPDATE of city
ON Suppliers
DECLARE 
    v_counter PLS_INTEGER;
BEGIN
    SELECT COUNT(*) 
      INTO v_counter
      FROM Projects p 
     WHERE lower(:new.city)=lower(p.city);

    IF (v_counter != 0) THEN
        raise_application_error(-20111,'Can''t change the city for this supplier!');
    END IF;
END;

如果v_计数器的初始化是冗余的,那么如果没有找到匹配的记录,它将已经为零。此外,请注意包含变量定义部分的declare关键字的顺序。

不需要连接开销,甚至不需要传输任何日期。假设在项目中对城市进行了索引,并且组件可能应该是一个索引的FK,那么以下内容只需要在每个表上创建一个简单的索引prob

create or replace trigger supplier_control
before update of city
on suppliers
for each row
declare 
    project_component_exists integer ;
begin
    select null
      into project_component_exists
      from dual
     where exists ( select null 
                      from projects  
                     where city = :old.city
                  ) 
       and exists ( select null 
                      from components  
                     where city = :old.city
                  );
    raise_application_error(-20111,'Can''t change the city for this supplier!');                  
exception 
 when no_data_found
 then null;    
end;   

不需要加入的开销,甚至不需要任何日期的转移。假设在项目中对城市进行了索引,并且组件可能应该是一个索引的FK,那么以下内容只需要在每个表上创建一个简单的索引prob

create or replace trigger supplier_control
before update of city
on suppliers
for each row
declare 
    project_component_exists integer ;
begin
    select null
      into project_component_exists
      from dual
     where exists ( select null 
                      from projects  
                     where city = :old.city
                  ) 
       and exists ( select null 
                      from components  
                     where city = :old.city
                  );
    raise_application_error(-20111,'Can''t change the city for this supplier!');                  
exception 
 when no_data_found
 then null;    
end;   

谢谢你的回复!我试过了,但是我仍然得到了一个错误,它说它在期望其他东西时遇到了JOIN。首先,运行查询SELECT COUNT*FROM SELECT*FROM供应商的JOIN项目p ON s.city=p.city JOIN组件c ON c.city=s.city如果输出是数字,则分配给变量v_counter谢谢您的回复!我试过了,但是我仍然得到一个错误,它说它在期望其他东西时遇到了JOIN。首先,运行查询SELECT COUNT*FROM SELECT*FROM供应商的JOIN项目p ON s.city=p.city JOIN Components c ON c.city=s.city如果输出是数字,那么就分配给变量v_counter在您的情况下,与其说创建了不允许更新的触发器,不如说您创建了一个会更新另一个拖车表的触发器,这将是一个稳健的设计。在您的情况下,与其说创建了不允许更新的触发器,不如说您创建了一个会更新另一个拖车表的触发器,这将是一个稳健的设计。