SQL trigger to stop update when a condition is met

不问归期 提交于 2019-12-13 06:22:26

问题


I have 3 tables: Projects, Components, and Suppliers.

What I am trying to do is writing a trigger that doesn't allow the value of city to be modified if the component and the project have the same city as the supplier.

What I have tried so far:

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;

After trying to run this, I am getting the following error:

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

Please note that the line number refers to the number of the line after BEGIN!

I have also tried writing the declare part before BEGIN, I am getting the following error:

Error at line 3: PL/SQL: SQL Statement ignored

What needs to be done in order to get rid of these errors?


回答1:


There are some syntax errors.

  1. DECLARE goes before the BEGIN statement.
  2. INTO goes after SELECT and before FROM.
  3. At raise_application_error(-20111,'Can't change the city for this supplier!'); you cannot write Can't because the first single quote will end at the quote of Can't causing the string to end there. So you should remove it or do: raise_application_error(-20111,'Can''t change the city for this supplier!');

With all that being said, the full code should look like:

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;

Hope this helps.




回答2:


You are trying to access the variable which is assigned as zero in the declaration. set the variable from the query (result of this will be a number)

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;

changed the count query to the edited one. First simply run the query SELECT COUNT(*) FROM (SELECT * FROM Suppliers s JOIN Projects p ON (s.city=p.city) JOIN Components c ON (c.city=s.city)) if the output is number then assign to the variable v_counter




回答3:


There is no need for the overhead of a Join nor even transfer of any date. Assuming City is indexed in Projects and Components (probably should be an indexed FK), the following requires only a simple index prob on each table.

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;   



回答4:


Check ,by lower() or upper() to match including case-insensitivity, whether a city match throughout the whole table Project's values.

You don't need to and shouldn't use Supplier table in the select statement due to risk of table name is mutating error :

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;

where an initialization is redundant for v_counter, if there's no matching record found it would already be zero. Moreover, notice the order of declare keyword including variable definition part with it.



来源:https://stackoverflow.com/questions/59125284/sql-trigger-to-stop-update-when-a-condition-is-met

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!