【问题标题】:PL/SQL DB Deployment ScriptPL/SQL DB 部署脚本
【发布时间】:2020-11-12 12:27:40
【问题描述】:

我正在尝试编写一个部署脚本,以便在 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_PRODUCTS * 第 6 行的错误: ORA-06550:第 6 行,第 1 列: PLS-00103:在预期以下之一时遇到符号“CREATE”:...

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

【问题讨论】:

  • PL/SQL 语言没有CREATE 关键字。您需要execute immediate 或其他方法。
  • @sqlplus 命令,而不是 SQL 甚至 PL/SQL 命令。它只能用于sqlplus 命令行。 PL/SQL 代码在服务器上运行,没有任何关于使用哪个客户端工具调用它甚至访问客户端上的文件的概念。
  • @a_horse_with_no_name 如果这是 SQL*Plus 脚本的一部分,但是,SQL*Plus 会在执行之前将引用的脚本嵌入到 PL/SQL 块中。不过,引用的脚本必须是有效的 PL/SQL。
  • @WilliamRobertson:你确定吗?这将需要 sqlplus 在将 PL/SQL 块发送到服务器之前解析 PL/SQL 主体并用实际文件内容替换对文件的引用。
  • 在第一个脚本中,最后缺少“/”。没有这个,它假定CREATE TABLE 是 PLSQL 块的一部分。

标签: oracle plsql sqlplus


【解决方案1】:

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

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

【讨论】:

  • 这是完美的。我开始在我的所有 DDL 脚本中添加 EXECUTE IMMEDIATE 并且不喜欢这种气味。
【解决方案2】:

正如其他人所说,SQL*PLus 理解/能力与 SQL 和 PLSQL 语言之间存在严格区分。

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

另外,SQL*Plus 对 PLSQL 逻辑结构没有任何了解。

但是,根据您的要求,可能会有办法。 @“Connor McDonald”的答案应该有效。这是我尝试使用更基于 PLSQL 的方法。

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

首先您需要一个“No Op”脚本,因为在使用 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 替换变量 (&),我们使用 COL ... NEW_VALUE 命令将 SELECT 列表列别名映射到替换变量。所以我们将有效地将scriptn 映射到子变量;e sn

PLSQL 块完成后,scriptn 变量将具有值“noop.sql”或要运行的脚本的名称。

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

任何带有“noop.sql”的东西都会执行一个空白脚本。

【讨论】:

    【解决方案3】:

    我自己没有使用过这个,但你可以试试这样的东西(简化演示):

    declare
        vnum number := 0;
    begin
        --select count(tname) into vnum from tab where tname = 'DA_VERSION';
        if vnum = 0 then -- include create script
            execute immediate q'[
            @callthis.sql
            ]';
         end if;
    end;
    

    要在execute immediate 内工作,被调用的脚本必须包含单个语句且不包含分号。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2010-11-20
      • 2012-05-19
      相关资源
      最近更新 更多