我有3个表:Projects
,Components
和Suppliers
。
[我想做的是编写一个触发器,如果组件和项目与供应商所在的城市相同,则不允许修改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
请注意,行号是指BEGIN之后的行号!
我也尝试过在BEGIN之前编写声明部分,但出现以下错误:
Error at line 3: PL/SQL: SQL Statement ignored
要摆脱这些错误需要做什么?
存在一些语法错误。
DECLARE
在BEGIN
语句之前。INTO
在SELECT
之后且在FROM
之前。raise_application_error(-20111,'Can't change the city for this supplier!');
,您不能写Can't
,因为第一个单引号将以Can't
的引号结束,导致字符串在此结束。因此,您应该删除它或执行以下操作:raise_application_error(-20111,'Can''t change the city for this supplier!');
话虽如此,完整的代码应如下所示:
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;
希望这会有所帮助。
您正在尝试访问在声明中分配为零的变量。设置查询中的变量(其结果将是数字)
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
不需要加入的开销,也不需要转移任何日期。假设City在Projects and Components中已建立索引(可能应该是在FK中建立索引),则以下内容仅需要在每个表上建立一个简单的索引概率。
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;
通过lower()
或upper()
进行检查以匹配,包括不区分大小写,在整个表项目的值中城市是否匹配。
由于表名发生更改错误的风险,因此您不需要,也不应在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_counter
的初始化是多余的,如果没有找到匹配的记录,则它已经为零。此外,请注意declare
关键字包含变量定义部分的顺序。