如何在 oracle 中有条件地执行 DDL?

Posted

技术标签:

【中文标题】如何在 oracle 中有条件地执行 DDL?【英文标题】:How to execute DDLs conditionally in oracle? 【发布时间】:2014-04-03 16:36:13 【问题描述】:

我有一个创建大量表、索引、触发器等的脚本。我想有条件地运行所有这些 DDL。我试图用 'if then' 包装脚本,但它不起作用

IF exists (select 1 from xxx where yyy) THEN

    create table...

    create table...

    CREATE UNIQUE INDEX ...

    CREATE TRIGGER ...

END IF;

我怎样才能做到这一点?

【问题讨论】:

【参考方案1】:

其中一种方式:

begin
    for cur in (select 1 from xxx where yyy and rownum <= 1) loop
     execute immediate 'create table...';
     execute immediate 'create table...';
     execute immediate 'create unique index...';
    end loop;
end;
/

附:另一种方法是生成异常并在 SQL*Plus 中继续。

文件example.sql:

SET ECHO OFF
SET VERIFY OFF
WHENEVER SQLERROR EXIT;

VAR x NUMBER
EXEC :x := &1
BEGIN
  FOR cur IN (SELECT 1 FROM dual WHERE 1=:x) LOOP
    RETURN;
  END LOOP;
  RAISE NO_DATA_FOUND;
END;
/

PROMPT Here we are

结果:

SQL> @example
Enter value for 1 1: 1

PL/SQL procedure completed.


PL/SQL procedure completed.

Here we are
SQL> @example
Enter value for 1: 2

PL/SQL procedure completed.

BEGIN
*
error in line 1:
ORA-01403: no data found
ORA-06512: in line 5 

当我使用值 2 时,块引发异常并且脚本存在 SQL*Plus。

附:再举一个例子——希望这能解决下面的问题。我仅在表不存在时创建表。表在 DEFAULT 语句中包含 1024 个分区和 ' 字符。文字大小 > 32K。

SQL> set serveroutput on
SQL> DECLARE
  2   sql_code clob;
  3   delim varchar2(1) := '';
  4   amount int;
  5   sql_text varchar2(32767);
  6  BEGIN
  7  
  8    dbms_lob.createtemporary(sql_code,cache => true);
  9    sql_text := q'[CREATE TABLE TEST_TAB (X INT PRIMARY KEY, Y VARCHAR2(10) DEFAULT 'DEF', Z INTEGER) PARTITION BY RANGE(Z) ( ]';
 10    amount := length(sql_text);
 11    dbms_lob.writeappend(sql_code,amount,sql_text);
 12  
 13    for i in 1..1024 loop
 14        sql_text := delim||'PARTITION P_'||i||' VALUES LESS THAN ('||i||')';
 15        amount := length(sql_text);
 16        dbms_lob.writeappend(sql_code,amount,sql_text);
 17        delim := ',';
 18    end loop;
 19  
 20    dbms_lob.writeappend(sql_code,1,')');
 21  
 22    FOR cur IN (
 23      SELECT * FROM dual WHERE NOT EXISTS (
 24             SELECT * FROM user_tables WHERE table_name = 'TEST_TAB')
 25    ) LOOP
 26      EXECUTE IMMEDIATE sql_code;
 27    END LOOP;
 28  
 29    dbms_output.put_line(dbms_lob.getlength(lob_loc => sql_code));
 30  
 31  END;
 32  /
39877                                                                           

PL/SQL procedure completed.

SQL> desc test_tab
 Имя                                       Пусто?   Тип
 ----------------------------------------- -------- ----------------------------
 X                                         NOT NULL NUMBER(38)
 Y                                                  VARCHAR2(10)
 Z                                                  NUMBER(38)

SQL> select count(*) from user_tab_partitions where table_name = 'TEST_TAB';

  COUNT(*)                                                                      
----------                                                                      
      1024                                       

【讨论】:

但这意味着我必须手动转义 ddls 中的所有撇号,以便为其创建/查找一些工具 您可以对字符值使用 q[''] Oracle 语法来避免手动操作。 @DmitryNikiforov,带括号的替代引用语法是q'[]' 您能否提供更多详细信息或指向此q['']q'[]' 的链接? 请看正文部分:docs.oracle.com/cd/E11882_01/server.112/e26088/…

以上是关于如何在 oracle 中有条件地执行 DDL?的主要内容,如果未能解决你的问题,请参考以下文章

如何在gdbinit函数中有条件地执行命令

oracle 如何看表的ddl

我如何知道在 Oracle 表上触发的所有 DDL?

如何在 Svelte 中有条件地禁用字段?

如何生成 Oracle 模式的整个 DDL(可编写脚本)?

如何在created()或mounted()中有条件地呈现JS