oracle - PLSQL : syntax problems with trigger

标签 oracle plsql triggers syntax-error

我已经创建了很多类似的触发器,因此习惯了发现常见的sntax错误-例如,忘记了END IF或THEN。我无法编译这个

CREATE OR REPLACE TRIGGER SOLD
BEFORE UPDATE OF STATUS ON STORE_COPY
FOR EACH ROW
DECLARE 
RENT_OR_SALE NVARCHAR2(6);
UPDATED_DVD_ID NUMBER(10);
BEGIN
UPDATED_DVD_ID := SELECT DVD_ID FROM STORE_COPY WHERE :NEW.STATUS != :OLD.STATUS;
RENT_OR_SALE := SELECT (SELECT RENT_OR_SALE FROM DVD JOIN STORE_COPY ON STORE_COPY.DVD_ID =     DVD.DVD_ID WHERE :NEW.STATUS != :OLD.STATUS) INTO RENT_OR_SALE FROM DUAL;
IF :NEW.STATUS != :OLD.STATUS
THEN
IF :OLD.STATUS = 'Y'
THEN
IF :NEW.STATUS = 'N'
THEN
IF RENT_OR_SALE = 'S'
THEN
INSERT INTO SOLD VALUES(NULL, CURRENT_TIMESTAMP, (SELECT PRICE FROM DVD JOIN STORE_COPY ON       STORE_COPY.DVD_ID = DVD.DVD_ID WHERE :NEW.DVD_IS = UPDATED_DVD_ID), :NEW.DVD_ID);
END IF;
END IF;
END IF;
END IF;
END;
/

终端通过“显示错误”命令为我提供了此信息:
Warning: Trigger created with compilation errors.

SQL> show errors;
LINE/COL ERROR
-------- -----------------------------------------------------------------
5/23     PLS-00103: Encountered the symbol "SELECT" when expecting one of
 the following:
 ( - + case mod new not null <an identifier>
 <a double-quoted delimited-identifier> <a bind variable>
 continue avg count current exists max min prior sql stddev
 sum variance execute forall merge time timestamp interval
 date <a string literal with character set specification>
 <a number> <a single-quoted SQL string> pipe
 <an alternatively-quoted string literal with character set
 specification>
 <an alternat

LINE/COL ERROR
-------- -----------------------------------------------------------------

6/5  PLS-00103: Encountered the symbol "RENT_OR_SALE" 

最佳答案

您需要使用SELECT...INTO...。 PL/SQL中没有variable := SELECT...。起点将是:

CREATE OR REPLACE TRIGGER SOLD
  BEFORE UPDATE OF STATUS ON STORE_COPY
  FOR EACH ROW
DECLARE 
  strRENT_OR_SALE NVARCHAR2(6);
  nUPDATED_DVD_ID NUMBER(10);
BEGIN
  SELECT DVD_ID
    INTO nUPDATED_DVD_ID
    FROM STORE_COPY
    WHERE :NEW.STATUS != :OLD.STATUS;

  SELECT RENT_OR_SALE
    INTO strRENT_OR_SALE
    FROM DVD
    JOIN STORE_COPY
      ON STORE_COPY.DVD_ID = DVD_ID
    WHERE :NEW.STATUS != :OLD.STATUS;

  IF :NEW.STATUS != :OLD.STATUS THEN
    IF :OLD.STATUS = 'Y' THEN
      IF :NEW.STATUS = 'N' THEN
        IF RENT_OR_SALE = 'S' THEN
          INSERT INTO SOLD VALUES
            (NULL,
             CURRENT_TIMESTAMP,
             (SELECT PRICE
                FROM DVD
                JOIN STORE_COPY
                  ON STORE_COPY.DVD_ID = DVD.DVD_ID
                WHERE :NEW.DVD_IS = UPDATED_DVD_ID),
             :NEW.DVD_ID);
        END IF;
      END IF;
    END IF;
  END IF;
END;

但是即使如此,您仍然会遇到错误。我怀疑那些SELECT是单例的(也就是说,它们可能返回多个行),因此它们将在运行时进行调整。即使您已完成该操作,仍然会遇到ORA-04091错误(表正在变异;触发器无法看到它),因为此触发器中有SELECT语句,该语句读取了该触发器是上。

您在这些SELECT FROM STORE_COPY...语句中尝试读取的值是否应该与刚刚修改的值相同?如果是这样,它们可以作为:OLD和:NEW值使用,因此以下方法可能有效:
CREATE OR REPLACE TRIGGER SOLD
  BEFORE UPDATE OF STATUS ON STORE_COPY
  FOR EACH ROW
DECLARE 
  strRENT_OR_SALE NVARCHAR2(6);
  nPrice          NUMBER;
BEGIN
  SELECT RENT_OR_SALE,
         PRICE
    INTO strRENT_OR_SALE,
         nPrice
    FROM DVD d
    WHERE d.DVD_ID = :NEW.DVD_ID

  IF :OLD.STATUS = 'Y' AND
     :NEW.STATUS = 'N' AND
     strRENT_OR_SALE = 'S'
  THEN
    INSERT INTO SOLD VALUES
      (NULL,
       CURRENT_TIMESTAMP,
       nPrice);
  END IF;
END TRIGGER_SOLD;

我可能在某些字段的位置上猜错了(例如,我猜PRICE在DVD上。如果实际上在STORE_COPY上,则可以改用:NEW.PRICE)。

分享并享受。

关于oracle - PLSQL : syntax problems with trigger,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/22334725/

相关文章:

php - 如何使用php日期函数从oracle日期字段中选择日期和时间

sql - PL/SQL ExcelDocumentType 文档名称错误

sql - ORA-06532 : Subscript outside of limit

Java 由 MySQL 触发器运行

Mysql 5.0 LAST_INSERT_ID()升级到5.6后有所不同

mysql - 如何使用包含总和和计数的 select 来触发 MySQL?

oracle - 我们可以在 PL/SQL 中使用线程吗?

oracle - ORA-01950 : no privileges on tablespace 'USERS'

sql - Oracle:相对日期和日期分区表

oracle - 即使有 CREATE table grant,Execute Immediate 也会失败