用于在表上自动生成 ID 的序列和触发 PL/SQL 脚本

Posted

技术标签:

【中文标题】用于在表上自动生成 ID 的序列和触发 PL/SQL 脚本【英文标题】:Sequence and Trigger PL/SQL script for Automatic ID generation on a table 【发布时间】:2013-08-07 13:23:13 【问题描述】:

谁能帮我修复那个代码。它不能在 PL/SQL (SQLPLUS @script.sql) 上运行,给出 SP2-0552:未声明绑定变量“NEW”。

脚本.SQL

  prompt Creating Table SYSTEMDATALOG;

declare 
    counter1 integer;
    counter2 integer;

begin
    SELECT COUNT(*) INTO counter1 FROM ALL_TABLES WHERE TABLE_NAME='SYSTEMDATALOG' AND OWNER='MZMESDB';

    if counter1 = 1 then 
        DROP TABLE SYSTEMDATALOG;
    end if;

    SELECT COUNT(*) INTO counter2 FROM ALL_SEQUENCES WHERE SEQUENCE NAME='SEQSYSTEMDATALOG';

    if counter2 = 1 then 
        DROP SEQUENCE SEQSYSTEMDATALOGID;
    endif;

    CREATE TABLE "MZMESDB"."SYSTEMDATALOG" ( "ID" INTEGER NOT NULL , 
                         "DATETIME" DATE NOT NULL , 
                         "TYPE" VARCHAR2(64) NOT NULL, 
                         "SEVERITY" INTEGER NOT NULL,
                         "SOURCE" VARCHAR2(64) NOT NULL, 
                         "USER" VARCHAR2(64) NOT NULL,
                         "MESSAGE" VARCHAR2(1024), PRIMARY KEY ("ID") VALIDATE );


    CREATE SEQUENCE SEQSYSTEMDATALOGID;

    CREATE OR REPLACE TRIGGER TRIGSYSTEMDATALOGID
        BEFORE INSERT ON SYSTEMDATALOG
        FOR EACH ROW
            BEGIN
                SELECT SEQSYSTEMDATALOGID.NEXTVAL INTO :NEW.ID FROM DUAL;
            END TRIGSYSTEMDATALOGID;
end;
/

提前感谢您的任何帮助。

[确定代码]

提示创建表SYSTEMDATALOG;

声明 counter1 整数; counter2 整数;

开始 SELECT COUNT(*) INTO counter1 FROM ALL_TABLES WHERE TABLE_NAME='SYSTEMDATALOG' AND OWNER='MZMESDB';

if counter1 = 1 then 
    execute immediate 'DROP TABLE SYSTEMDATALOG';
end if;

SELECT COUNT(*) INTO counter2 FROM ALL_SEQUENCES WHERE SEQUENCE_NAME='SEQSYSTEMDATALOG';

IF counter2 = 1 then
    execute immediate 'DROP SEQUENCE SEQSYSTEMDATALOGID';
END IF;

execute immediate 'CREATE TABLE "MZMESDB"."SYSTEMDATALOG" ( 
                    "ID" INTEGER NOT NULL , 
                    "DATETIME" DATE NOT NULL , 
                    "TYPE" VARCHAR2(64) NOT NULL, 
                    "SEVERITY" INTEGER NOT NULL,
                    "SOURCE" VARCHAR2(64) NOT NULL, 
                    "USER" VARCHAR2(64) NOT NULL,
                    "MESSAGE" VARCHAR2(1024), PRIMARY KEY ("ID") VALIDATE )';

execute immediate 'CREATE SEQUENCE SEQSYSTEMDATALOGID';

execute immediate 'CREATE OR REPLACE TRIGGER TRIGSYSTEMDATALOGID
           BEFORE INSERT ON SYSTEMDATALOG
           FOR EACH ROW
           BEGIN
            SELECT SEQSYSTEMDATALOGID.NEXTVAL INTO :NEW.ID FROM DUAL;
           END TRIGSYSTEMDATALOGID;';

结束;

【问题讨论】:

【参考方案1】:

一个问题是您正在混合使用 PL/SQL(一个匿名 PL/SQL 块)和 DDL。虽然您可以在 PL/SQL 中编写 DML 语句(SELECT/INSERT/UPDATE/DELETE),但您不能直接在 PL/SQL 中编写 DDL(CREATE/DROP 等)。

您需要在匿名 PL/SQL 块之外运行 DDL 语句或使用 EXECUTE IMMEDIATE '<statement>';.

至于:NEW 上的错误,我认为当您解决其他问题时它会消失。如果没有,请尝试添加:

SET SCAN OFF

在 SQL*Plus 文件的开头。

【讨论】:

我使用 EXECUTE IMMEDIATE 也没有成功。我更改了脚本,因为它不起作用... 您的立即执行代码中有一些语法错误: 1. end if; 拼写错误为 endif; 2. 一些字符串常量没有被撇号包围(SYSTEMDATALOG 应该是 @987654327 @)。 Endif 确实是一个错误。我试过带引号和不带引号,行为是一样的。即使修复了 endif,当 PL/SQL 处理器的最后一行出现以下情况之一时,我仍然会得到“遇到符号“;”。 我试过了(虽然我用SELECT 1 FROM DUAL交换了所有DDL),当我修复endif时,错误消息消失了。 我更改了帖子标题并添加了最终的工作代码。浪费了几个小时,但这对其他人可能有用。感谢您的帮助。

以上是关于用于在表上自动生成 ID 的序列和触发 PL/SQL 脚本的主要内容,如果未能解决你的问题,请参考以下文章

如何在表上创建复合主键 [重复]

尝试在“插入”之后将 ID(由触发器/序列生成)返回给变量

在表上创建复杂触发器

用于从序列生成 id 的 Oracle 触发器的 HIbernate 问题

如何在 Oracle 上使用 AUTO_INCREMENT 创建 id?

ORACLE 10g 自动递增触发器/序列不按编程递增