Oracle PL/SQL数据库部署脚本

Oracle PL/SQL数据库部署脚本,oracle,plsql,sqlplus,Oracle,Plsql,Sqlplus,我正试图编写一个部署脚本,在CI/CD管道中使用SQL*Plus运行,但我找不到解决这个看似非常基本的问题的方法 下面是脚本release.sql的缩短版本: DECLARE vnum NUMBER; BEGIN SELECT COUNT(tname) INTO vnum FROM tab WHERE tname = 'DA_VERSION'; IF vnum = 0 THEN -- run create scripts @ddl/da_001.sql

我正试图编写一个部署脚本,在CI/CD管道中使用SQL*Plus运行,但我找不到解决这个看似非常基本的问题的方法

下面是脚本release.sql的缩短版本:

DECLARE
    vnum NUMBER;
BEGIN
    SELECT COUNT(tname) INTO vnum FROM tab WHERE tname = 'DA_VERSION';
    IF vnum = 0 THEN -- run create scripts
        @ddl/da_001.sql
        @ddl/da_002.sql
        @dml/version.sql -- set initial version   
    END IF;
END;
da_001.sql如下所示:

CREATE TABLE TABLE_NAME 
(
  COLUMN1 NUMBER NOT NULL 
, CONSTRAINT TABLE_NAME_PK PRIMARY KEY 
  (
    COLUMN1 
  )
  ENABLE 
);
当我跑的时候

sqlplus.exe connection_string @release.sql
我明白了

创建表DA_产品 * 第6行错误: ORA-06550:第6行第1列: PLS-00103:在预期以下情况时遇到符号“创建”:


所以它不喜欢da_001.sql开头的CREATE语句,但我不知道为什么。我在这里缺少什么?

我自己没有用过,但您可以尝试类似的方法(简化演示):


要在
executeimmediate
中工作,调用的脚本必须包含一条语句,且不包含分号。

为脚本创建一个安装文件,即

install.sql
===========
@ddl/da_001.sql
@ddl/da_002.sql
@dml/version.sql -- set initial version   
然后在SQL Plus中通过包装器有选择地调用它

set feedback off
set pages 0
spool /tmp/runme.sql
select 
  case when COUNT(tname) = 0 then '@@install.sql' else 'pro Skipped install.sql' end
FROM tab WHERE tname = 'DA_VERSION';
spool off
@/tmp/runme.sql

正如其他人所说,SQL*PLus理解/能够理解的内容与SQL和PLSQL语言内部的内容之间存在着严格的分离

脚本处理是这些不同的领域之一,这意味着您不能在PLSQL块中执行SQL脚本

此外,SQL*Plus对PLSQL逻辑结构没有任何理解

然而,考虑到您的需求,可能有一种方法。“康纳·麦克唐纳”的回答应该有效。下面是我使用基于PLSQL的方法的尝试

这种方法使用SQLPLus变量,可以在PLSQL和SQLPLus中引用和修改这些变量

首先,您需要一个“无操作”脚本,因为在使用SQL*PLus“@”时,必须指定一个有效的脚本名称:

noop.sql:

PROMPT No Op
现在,您的控制器脚本:

-- Declare your variables 

VAR script1 VARCHAR2(256)
VAR script2 VARCHAR2(256)
VAR script3 VARCHAR2(256)

DECLARE
    vnum NUMBER;
BEGIN
    :script1 := 'noop.sql';
    :script2 := 'noop.sql';
    :script3 := 'noop.sql';
    SELECT COUNT(tname) INTO vnum FROM tab WHERE tname = 'DA_VERSION';
    IF vnum = 0 THEN -- run create scripts
         -- Set variables
        :script1 := 'ddl/da_001.sql';
        :script2 := 'ddl/da_002.sql';
        :script3 := 'dml/version.sql'; -- set initial version   
    END IF;
END;
/

-- Make variables referencable as SQLPLus defines

COLUMN s1 NEW_VALUE s1
COLUMN s2 NEW_VALUE s2
COLUMN s3 NEW_VALUE s3

SELECT :script1 s1, :script2 s2, :script3 s3
FROM dual;

-- RUN !!

@ &&s1
@ &&s2
@ &&s3
3个
scriptn
变量可以在PLSQL中使用

要用作SQL_PLus substation变量(&),我们使用
列。。。NEW_VALUE
命令将选择列表列别名映射到替换变量。因此,我们将有效地将
scriptn
映射到子变量bl;e
sn

PLSQL块完成后,
scriptn
变量的值为'noop.sql'或要运行的脚本的名称

最后,在“@”命令中引用subs变量


任何带有'noop.sql'的内容都将执行一个空白脚本。

PL/sql语言没有
CREATE
关键字。您需要
立即执行
或其他方法。
@
是一个
sqlplus
命令,而不是SQL甚至PL/SQL命令。它只能在
sqlplus
命令行上使用。PL/SQL代码在服务器上运行时,不知道使用哪个客户端工具调用它,甚至不知道如何访问客户端上的文件。@如果这是SQL*Plus脚本的一部分,则SQL*Plus会在执行之前将引用的脚本嵌入PL/SQL块中。不过,引用的脚本必须是有效的PL/SQL。@WilliamRobertson:你确定吗?这需要sqlplus解析PL/SQL正文,并在将PL/SQL块发送到服务器之前用实际的文件内容替换对文件的引用。在第一个脚本中,结尾缺少“/”。如果没有这一点,它将假定
创建表
是PLSQL块的一部分。这是完美的。我开始将executeimmediate添加到我所有的DDL脚本中,不喜欢这种味道。
-- Declare your variables 

VAR script1 VARCHAR2(256)
VAR script2 VARCHAR2(256)
VAR script3 VARCHAR2(256)

DECLARE
    vnum NUMBER;
BEGIN
    :script1 := 'noop.sql';
    :script2 := 'noop.sql';
    :script3 := 'noop.sql';
    SELECT COUNT(tname) INTO vnum FROM tab WHERE tname = 'DA_VERSION';
    IF vnum = 0 THEN -- run create scripts
         -- Set variables
        :script1 := 'ddl/da_001.sql';
        :script2 := 'ddl/da_002.sql';
        :script3 := 'dml/version.sql'; -- set initial version   
    END IF;
END;
/

-- Make variables referencable as SQLPLus defines

COLUMN s1 NEW_VALUE s1
COLUMN s2 NEW_VALUE s2
COLUMN s3 NEW_VALUE s3

SELECT :script1 s1, :script2 s2, :script3 s3
FROM dual;

-- RUN !!

@ &&s1
@ &&s2
@ &&s3