无法弄清楚这个 SQL 触发器

Cant figure out this SQL Trigger

所以我想为我的数据库创建一个触发器,这将限制可以分配多少 类 个教员。如果 QUALIFIED = 'Y',那么他们最多可以教三个 类。我 运行 遇到的麻烦是我不知道我的 SQL 声明有什么问题不会让它成为 运行.

CREATE OR REPLACE trigger "ASSIGN_T1"
BEFORE
INSERT ON "ASSIGN"
FOR EACH ROW

BEGIN
    DECLARE
         A_COUNT NUMBER;
         A_QUALIFY CHAR(2);
    
    SET(SELECT QUALIFY FROM QUALIFY WHERE (FID = :NEW.FID)) AS A_QUALIFY
    SET(SELECT COUNT(FID) FROM QUALIFY WHERE (FID = :NEW.FID)) AS A_COUNT

    IF (A_QUALIFY = 'Y' AND A_COUNT < 3) THEN
           INSERT INTO ASSIGN (FID, CID) VALUES (:NEW.FID, :NEW.CID);
    END IF;
END;

我遇到的两个错误是

line 8, position 8 PLS-00103: Encountered the symbol "(" when expecting one of the following: constant exception table long double ref char time timestamp

line 8, position 61 PLS-00103: Encountered the symbol "AS" when expecting one of the following: set

这里的第一个问题是 BEGIN 需要向下移动到 DECLARE 和变量声明之下。

第二个问题是您尝试设置这些变量的方式。摆脱那些 SET 和 AS。在 PL/SQL 中,使用 SQL 语句的结果设置变量的一种有效方法是使用 SELECT INTO。像这样....

  SELECT QUALIFY
  INTO A_QUALIFY
  FROM QUALIFY
  WHERE FID = :NEW.FID;

...您可以对 A_COUNT

执行相同的操作

我不保证在您执行此操作后一切都会立即正常运行,但这是此处修复的最低限度。

此外,即使执行了上述工作,也要注意 SELECT INTO,因为如果有 ever 场景,您将收到“未找到数据”错误如果您还没有 FID = :NEW.FID 传入或“精确获取 returns 超过请求的行数”错误,如果您的 FID 中有超过 1 个现有记录table。然后,您要么必须处理这些异常,要么使用不同的方法为变量赋值(例如在游标中声明 SQL,然后打开游标、FETCH 游标进入变量、关闭游标。)

最后,我觉得你的逻辑可能有问题。您要求 FID 的 QUALIFY 中的值,但随后您要求具有该 FID 的记录数。这意味着 FID 不是您 table 上的主键,这意味着可能有不同的记录具有相同的 FID 但 QUALIFY 字段中的值不同。因此,如果您稍后要在您的逻辑中使用该变量,那么这可能是个问题,因为同一个 FID 可以有一个 QUALIFY = 'Y' 的记录,而另一个 QUALIFY = [=26 的记录=]

您已经使用了 BEGIN after DECLARE 部分。并且不确定您为什么使用 SET .. AS。我们可以将两个selects合二为一,在IF条件下使用。

我认为您不能在同一个 table 上触发并同时插入。您最终会遇到 ORA-04088 错误。

相反,您可以通过抛出错误来限制插入。 (我的选择是对 ASSIGN table 的外键约束)

--Creating Tables
   create table ASSIGN  (FID number,      CID number);
   create table QUALIFY (FID number,    QUALIFY char);
    
-- Loading sample data
insert into QUALIFY values (1, 'Y');
insert into QUALIFY values (1, 'Y');
insert into QUALIFY values (1, 'Y');
insert into QUALIFY values (2, 'Y');
insert into QUALIFY values (2, 'Y');
insert into QUALIFY values (3, 'N');
insert into QUALIFY values (4, 'Y');

CREATE OR REPLACE trigger "ASSIGN_T1"
BEFORE
INSERT ON "ASSIGNEE" --< change table name to yours
FOR EACH ROW
 DECLARE
     A_COUNT NUMBER;
 BEGIN    
  SELECT COUNT(QUALIFY) into A_COUNT FROM QUALIFY WHERE QUALIFY='Y' AND FID = :NEW.FID;
    
  -- If they are qualified and already has 3 classes. They are not allowed/record is not inserted.
  IF  A_COUNT = 3 THEN
  Raise_Application_Error (-20343, 'FID is not Qualified or already has 3 Classes.');
  END IF;
 END;
/

通过将数据插入 ASSIGNEE 进行测试 table

-- FID 1 already assigned to 3 classes, should not be allowed any more.
insert into ASSIGNEE values (1,3);
-- See error below
Error report -
ORA-20343: FID is not Qualified or already has 3 Classes.

-- FID 2 has only 2 classes, so allowed to insert.
insert into ASSIGNEE values (2,3);
1 row inserted.

实现目标的一种方法是执行以下操作:

CREATE OR REPLACE TRIGGER ASSIGN_T1
  BEFORE INSERT ON ASSIGN
  FOR EACH ROW
BEGIN
  FOR aRow IN (SELECT q.QUALIFY,
                      COUNT(*) OVER (PARTITION BY q.FID) AS FID_COUNT
                 FROM QUALIFY q
                 WHERE q.FID = :NEW.FID)
  LOOP
    IF aRow.QUALIFY = 'Y' AND aRow.FID_COUNT < 3 THEN
      INSERT INTO ASSIGN (FID, CID) VALUES (:NEW.FID, :NEW.CID);
    END IF;
  END LOOP;
END ASSIGN_T1;