问题
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.
DECLARE
goes before theBEGIN
statement.INTO
goes afterSELECT
and beforeFROM
.- At
raise_application_error(-20111,'Can't change the city for this supplier!');
you cannot writeCan't
because the first single quote will end at the quote ofCan'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