存储过程在 TOAD 中运行良好,但在 SQL Plus 中运行不正常,并给出错误 Bind variable NEW not declared?

Stored procedure is working fine in TOAD but not working in SQL Plus and giving error Bind variable NEW not declared?

SP 在 TOAD 中工作正常但在 SQL*PLUS 中不工作。它抱怨触发器中使用了 new 关键字。我正在使用 SET SQLBLANKLINES ON 语句以及我已经阅读过它可能是因为空白 space 但仍然出现错误,不确定触发器的语法有什么问题对我来说看起来很好但它给出了低于错误

SET SQLBLANKLINES ON;
SET DEFINE OFF;

BEGIN 
DECLARE
  cnt_master   NUMBER;
BEGIN
   SELECT COUNT (1)
   INTO cnt_master
   FROM all_objects
   WHERE
         UPPER (object_type) = UPPER ('TABLE')
         AND UPPER (object_name) = UPPER ('USER_LNG_DAILY_LIMITS_COMP')
         AND UPPER (Owner) IN (SELECT SYS_CONTEXT ('USERENV','CURRENT_SCHEMA') FROM DUAL);

  IF cnt_master = 0
  THEN
     BEGIN
        EXECUTE IMMEDIATE ('
        CREATE TABLE USER_LNG_DAILY_LIMITS_COMP
        (
            COMPONENT_ID      NUMBER(10) PRIMARY KEY NOT NULL, 
            TITLE             VARCHAR2 (255),
            USER_ID           NUMBER(10),
            LAST_UPDATE       DATE
        )');
        EXECUTE IMMEDIATE
           ('GRANT DELETE, INSERT, SELECT, UPDATE ON USER_LNG_DAILY_LIMITS_COMP TO OLF_USER');
        EXECUTE IMMEDIATE
           ('GRANT SELECT ON  USER_LNG_DAILY_LIMITS_COMP TO OLF_READONLY');
     END;
  END IF;
END;
END;

                
 BEGIN 
 DECLARE
   cnt_master   NUMBER;
 BEGIN
   SELECT COUNT (1)
   INTO cnt_master
   FROM all_objects
   WHERE
         UPPER (object_type) = UPPER ('SEQUENCE')
         AND UPPER (object_name) = UPPER ('USER_LNG_DAILY_LIMITS_COMP_SQ')
         AND UPPER (Owner) IN (SELECT SYS_CONTEXT ('USERENV','CURRENT_SCHEMA') FROM DUAL);

  IF cnt_master = 0
  THEN
     BEGIN
        EXECUTE IMMEDIATE
           ('CREATE SEQUENCE USER_LNG_DAILY_LIMITS_COMP_SQ START WITH 1 INCREMENT BY 1');
     END;
  END IF;
 END;
 END;


CREATE OR REPLACE trigger USER_LNG_DAILY_LIMITS_COMP_TR
BEFORE INSERT ON USER_LNG_DAILY_LIMITS_COMP
FOR EACH ROW
BEGIN
      SELECT USER_LNG_DAILY_LIMITS_COMP_SQ.NEXTVAL INTO :new.COMPONENT_ID FROM dual;          
END;

您需要一个单独的斜杠 (/) 来终止新行,并且 运行 一个 PL/SQL 块。 From the SQL*Plus documentation:

SQL*Plus stores the subprograms you enter in the SQL buffer. Execute the current subprogram with a RUN or slash (/) command. A semicolon (;) is treated as part of the PL/SQL subprogram and will not execute the command.

因此您的脚本结构需要是:

SET SQLBLANKLINES ON;
SET DEFINE OFF;

DECLARE
  cnt_master   NUMBER;
BEGIN
  SELECT COUNT (1)
  INTO cnt_master
  FROM all_objects
  WHERE
        UPPER (object_type) = UPPER ('TABLE')
        AND UPPER (object_name) = UPPER ('USER_LNG_DAILY_LIMITS_COMP')
        AND UPPER (Owner) IN (SELECT SYS_CONTEXT ('USERENV','CURRENT_SCHEMA') FROM DUAL);

  IF cnt_master = 0
  THEN
     BEGIN
        EXECUTE IMMEDIATE ('
        CREATE TABLE USER_LNG_DAILY_LIMITS_COMP
        (
            COMPONENT_ID      NUMBER(10) PRIMARY KEY NOT NULL, 
            TITLE             VARCHAR2 (255),
            USER_ID           NUMBER(10),
            LAST_UPDATE       DATE
        )');
        EXECUTE IMMEDIATE
           ('GRANT DELETE, INSERT, SELECT, UPDATE ON USER_LNG_DAILY_LIMITS_COMP TO OLF_USER');
        EXECUTE IMMEDIATE
           ('GRANT SELECT ON  USER_LNG_DAILY_LIMITS_COMP TO OLF_READONLY');
     END;
  END IF;
END;
/
                
DECLARE
  cnt_master   NUMBER;
BEGIN
  SELECT COUNT (1)
  INTO cnt_master
  FROM all_objects
  WHERE
        UPPER (object_type) = UPPER ('SEQUENCE')
        AND UPPER (object_name) = UPPER ('USER_LNG_DAILY_LIMITS_COMP_SQ')
         AND UPPER (Owner) IN (SELECT SYS_CONTEXT ('USERENV','CURRENT_SCHEMA') FROM DUAL);

  IF cnt_master = 0
  THEN
     BEGIN
        EXECUTE IMMEDIATE
           ('CREATE SEQUENCE USER_LNG_DAILY_LIMITS_COMP_SQ START WITH 1 INCREMENT BY 1');
     END;
  END IF;
END;
/

CREATE OR REPLACE trigger USER_LNG_DAILY_LIMITS_COMP_TR
BEFORE INSERT ON USER_LNG_DAILY_LIMITS_COMP
FOR EACH ROW
BEGIN
  :new.COMPONENT_ID := USER_LNG_DAILY_LIMITS_COMP_SQ.NEXTVAL;          
END;
/

-- other commands

不是触发器的主体 is also PL/SQL,因此应该终止并 运行 用斜杠和匿名块。

我已经从每个块中删除了 begin/end 的冗余级别 - 实际上没有功能差异,但它们只是不需要。我还更改了序列值分配(如@pmdba 所述)——除非您使用的是真正旧版本的 Oracle,否则您不需要将上下文切换到 select,从 dual.