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

SQL trigger to stop update when a condition is met

我有 3 个表:ProjectsComponentsSuppliers

我想做的是编写一个触发器,如果​​组件和项目与供应商具有相同的城市,则不允许修改 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

需要做什么才能消除这些错误?

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

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

有些语法错误。

  1. DECLAREBEGIN 语句之前。
  2. INTOSELECT 之后和 FROM 之前。
  3. 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;

希望这对您有所帮助。

检查 lower()upper() 匹配包括不区分大小写,城市是否匹配整个 table 项目的值。

您不需要也不应该在 select 声明中使用 Supplier table,因为 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;

v_counter 的初始化是多余的,如果没有找到匹配的记录,它就已经是零了。此外,请注意 declare 关键字的顺序,包括变量定义部分。

不需要 Join 的开销,甚至不需要转移任何日期。假设 City 在 Projects 和 Components 中被索引(可能应该是一个索引的 FK),下面只需要在每个 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;