• 读书笔记:SQL 查询中的SQL*Plus 替换变量(DEFINE变量)和参数


    本文为“SQL*Plus 替换变量 - 在 SQL 查询中定义变量和参数”的读书笔记。

    此文主要是讲替换变量,也称为DEFINE变量,但也涉及了绑定变量和SQL Plus系统变量。

    这篇文章展示了替换变量如何替换 Oracle SQL 和 SQL*Plus 语句中的硬编码文本。

    向作者致敬,尽管是10多年前的文章,但写的非常好和全面,仍具重要参考价值。

    1 介绍

    本文档解释了 SQLPlus 替换变量如何工作以及它们可以在哪里使用。 它显示了 SQLPlus 中使用的三种类型的变量(替换、绑定和系统)之间的关系。

    替换变量可以替换 SQLPlus 命令选项或其他硬编码文本。 它们可用于自定义 SQLPlus 脚本输出。 语句中的替换变量引用在 SQL*Plus 执行语句之前被预处理和替换。 变量值可以预定义、提示输入或设置为脚本参数。 变量还可以保存从查询返回的值。 有时替换变量称为用户变量或定义变量。

    替换变量的例子为:

    SQL> define
    DEFINE _DATE           = "22-JUN-22" (CHAR)
    DEFINE _CONNECT_IDENTIFIER = "orclpdb1" (CHAR)
    DEFINE _USER           = "SSB" (CHAR)
    DEFINE _PRIVILEGE      = "" (CHAR)
    DEFINE _SQLPLUS_RELEASE = "2103000000" (CHAR)
    DEFINE _EDITOR         = "vi" (CHAR)
    DEFINE _O_VERSION      = "Oracle Database 21c Enterprise Edition Release 21.0.0.0.0 - Production
    Version 21.3.0.0.0" (CHAR)
    DEFINE _O_RELEASE      = "2103000000" (CHAR)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    绑定变量存储在 RDBMS 中执行的 SQL 和 PL/SQL 语句的数据值。 它们可以保存单个值或完整的结果集。

    系统变量包含直接控制 SQL*Plus 的值,例如报表的行大小和页面大小。 一些系统变量会影响替换变量的处理方式。 系统变量有时称为 SET 变量。

    系统变量的例子为:

    SQL> show all
    appinfo is OFF and set to "SQL*Plus"
    arraysize 15
    autocommit OFF
    autoprint OFF
    autorecovery OFF
    autotrace OFF
    blockterminator "." (hex 2e)
    btitle OFF and is the first few characters of the next SELECT statement
    cmdsep OFF
    colinvisible OFF
    coljson OFF
    colsep " "
    compatibility version NATIVE
    concat "." (hex 2e)
    copycommit 0
    COPYTYPECHECK is ON
    define "&" (hex 26)
    describe DEPTH 1 LINENUM OFF INDENT ON
    echo OFF
    editfile "afiedt.buf"
    embedded OFF
    errorlogging is OFF
    escape OFF
    escchar OFF
    exitcommit ON
    FEEDBACK ON for 6 or more rows SQL_ID OFF
    flagger OFF
    flush ON
    fullcolname OFF
    heading ON
    headsep "|" (hex 7c)
    history is OFF
    instance "local"
    jsonprint NORMAL
    linesize 80
    lno 14
    loboffset 1
    lobprefetch 0
    logsource ""
    long 80
    longchunksize 80
    markup HTML OFF HEAD "<style type='text/css'> body {font:10pt Arial,Helvetica,sans-serif; color:black; background:White;} p {font:10pt Arial,Helvetica,sans-serif; color:black; background:White;} table,tr,td {font:10pt Arial,Helvetica,sans-serif; color:Black; background:#f7f7e7; padding:0px 0px 0px 0px; margin:0px 0px 0px 0px;} th {font:bold 10pt Arial,Helvetica,sans-serif; color:#336699; background:#cccc99; padding:0px 0px 0px 0px;} h1 {font:16pt Arial,Helvetica,Geneva,sans-serif; color:#336699; background-color:White; border-bottom:1px solid #cccc99; margin-top:0pt; margin-bottom:0pt; padding:0px 0px 0px 0px;-
    } h2 {font:bold 10pt Arial,Helvetica,Geneva,sans-serif; color:#336699; background-color:White; margin-top:4pt; margin-bottom:0pt;} a {font:9pt Arial,Helvetica,sans-serif; color:#663300; background:#ffffff; margin-top:0pt; margin-bottom:0pt; vertical-align:top;}</style><title>SQL*Plus Report</title>" BODY "" TABLE "border='1' width='90%' align='center' summary='Script output'" SPOOL OFF ENTMAP ON PREFORMAT OFF
    markup CSV OFF DELIMITER , QUOTE ON
    newpage 1
    null ""
    numformat ""
    numwidth 10
    pagesize 14
    PAUSE is OFF
    pno 0
    recsep WRAP
    recsepchar " " (hex 20)
    release 2103000000
    repfooter OFF and is NULL
    repheader OFF and is NULL
    rowlimit OFF
    rowprefetch 1
    securedcol is OFF
    serveroutput OFF
    shiftinout INVISIBLE
    showmode OFF
    spool OFF
    sqlblanklines OFF
    sqlcase MIXED
    sqlcode 0
    sqlcontinue "> "
    sqlnumber ON
    sqlpluscompatibility 21.0.0
    sqlprefix "#" (hex 23)
    sqlprompt "SQL> "
    sqlterminator ";" (hex 3b)
    statementcache is 0
    suffix "sql"
    tab ON
    termout ON
    timing OFF
    trimout ON
    trimspool OFF
    ttitle OFF and is the first few characters of the next SELECT statement
    underline "-" (hex 2d)
    USER is "SSB"
    verify ON
    wrap : lines will be wrapped
    xmloptimizationcheck OFF
    
    SQL> show release
    release 2103000000
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89

    2 使用替换变量

    2.1 创建、显示和删除替换变量

    可以使用 DEFINE 命令显式创建替换变量。 定义变量意味着存储一个值以供将来使用。

    SQL> define myv = 'King'
    
    • 1

    创建替换变量的另一种方法是使用 ACCEPT 命令。 这可用于提示输入值:

    SQL> accept myv2 char prompt 'Enter a last name: '
    
    • 1

    查看所有或指定的替换变量:

    SQL> define
    ...
    DEFINE MYV             = "King" (CHAR)
    DEFINE MYV2            = "amigo" (CHAR)
    
    SQL> define myv
    DEFINE MYV             = "King" (CHAR)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    可以使用 UNDEFINE 命令删除替换变量:

    SQL> undefine myv
    
    SQL> define myv
    SP2-0135: symbol myv is UNDEFINED
    
    • 1
    • 2
    • 3
    • 4

    2.2 引用替换变量

    可以通过在其名称前加上与号 (&) 来引用变量:

    -- HR sample schema
    define myv = 'King'
    select employee_id from employees where last_name = '&myv';
    
    old   1: select employee_id from employees where last_name = '&myv'
    new   1: select employee_id from employees where last_name = 'King'
    
    EMPLOYEE_ID
    -----------
            156
            100
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    如果不想显示替换前后的值,可以用SET VERIFY OFF:

    SQL> set verify off
    SQL> select employee_id from employees where last_name = '&myv';
    
    EMPLOYEE_ID
    -----------
            156
            100
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    其实这里的verify即系统变量:

    SQL> show verify
    verify OFF
    
    • 1
    • 2

    2.3 提示未定义的变量

    如果使用“&”前缀引用变量,但尚未定义变量值,SQL*Plus 会提示您输入值:

    SQL> define myname
    SP2-0135: symbol myname is UNDEFINED
    SQL> select employee_id from employees where last_name = '&myname';
    Enter value for myname: King
    
    EMPLOYEE_ID
    -----------
            156
            100
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    Oracle 全球化语言设置(例如 NLS_LANG 环境变量的语言组件)确定用于“输入值”提示的确切语言。 提示文本不能以其他方式更改。

    2.4 “&”和“&&”前缀的区别

    先看一个示例:

    SQL> prompt Querying table &mytable
    Enter value for mytable: employees
    Querying table employees
    SQL> define mytable
    SP2-0135: symbol mytable is UNDEFINED
    
    SQL> prompt Querying table &&mytable
    Enter value for mytable: employees
    Querying table employees
    SQL> define mytable
    DEFINE MYTABLE         = "employees" (CHAR)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    单与号 (&) 和双与号 (&&) 都可以在语句中作为替换变量名称的前缀。 SQL*Plus 预处理语句并替换变量的值。 然后执行该语句。 如果变量之前没有定义,那么 SQL Plus 会在进行替换之前提示您输入一个值。

    如果单个 & 号前缀与未定义的变量一起使用,则不会存储您在提示符处输入的值。 在语句中替换值之后,该变量立即被丢弃并保持未定义。 如果变量被引用两次,即使是在同一个语句中,也会提示您两次。 每次提示可以输入不同的值。

    如果双 & 号引用导致 SQLPlus 提示您输入值,则 SQLPlus 将变量定义为该值(即,该值将存储到您退出)。 使用“&”或“&&”对变量的任何后续引用(即使在同一命令中)都会替换新定义的值。 SQL*Plus 不会再次提示您。

    再来看一个复杂点的例子:

    SQL> undefine mytable
    SQL> prompt Querying table &mytable &mytable
    Enter value for mytable: a
    Enter value for mytable: b
    Querying table a b
    SQL> prompt Querying table &&mytable &mytable
    Enter value for mytable: a
    Querying table a a
    SQL> prompt Querying table &&mytable &mytable
    Querying table a a
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    2.5 将查询列值存储在替换变量中

    存储在数据库中的数据可以放入替换变量中。

    SQL> column last_name new_value mynv
    SQL> select last_name from employees where employee_id = 100;
    
    LAST_NAME
    -------------------------
    King
    
    SQL> define mynv
    DEFINE MYNV            = "King" (CHAR)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    COLUMN 命令中的 NEW_VALUE 选项隐式创建了一个名为“mynv”的替换变量。 在查询引用 LAST_NAME 列之前,不会实际创建该变量。 查询完成后,变量“mynv”保存从列“last_name”中最后检索到的值。

    2.6 预定义的替换变量

    启动 SQL*Plus 时创建的预定义替换变量可以通过输入不带参数的 DEFINE 来查看。 每个预定义变量都带有下划线前缀。 预定义变量可以像用户定义的替换变量一样未定义或重新定义。

    -- 我的笔记本
    SQL> define
    DEFINE _DATE           = "23-JUN-22" (CHAR)
    DEFINE _CONNECT_IDENTIFIER = "orclpdb1" (CHAR)
    DEFINE _USER           = "HR" (CHAR)
    DEFINE _PRIVILEGE      = "" (CHAR)
    DEFINE _SQLPLUS_RELEASE = "2103000000" (CHAR)
    DEFINE _EDITOR         = "vi" (CHAR)
    DEFINE _O_VERSION      = "Oracle Database 21c Enterprise Edition Release 21.0.0.0.0 - Production
    Version 21.3.0.0.0" (CHAR)
    DEFINE _O_RELEASE      = "2103000000" (CHAR)
    
    -- 云端实例
    SQL> define
    DEFINE _DATE           = "23-JUN-22" (CHAR)
    DEFINE _CONNECT_IDENTIFIER = "orclpdb1" (CHAR)
    DEFINE _USER           = "SSB" (CHAR)
    DEFINE _PRIVILEGE      = "" (CHAR)
    DEFINE _SQLPLUS_RELEASE = "2106000000" (CHAR)
    DEFINE _EDITOR         = "vi" (CHAR)
    DEFINE _O_VERSION      = "Oracle Database 21c EE Extreme Perf Release 21.0.0.0.0 - Production
    Version 21.6.0.0.0" (CHAR)
    DEFINE _O_RELEASE      = "2106000000" (CHAR)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23

    SQL Plus 10.1 中引入了变量_DATE、_PRIVILEGE 和_USER。 SQL Plus 9.2 中引入了变量_CONNECT_IDENTIFIER。 SQL Plus 18 中引入了变量 _SQL_ID。

    • _CONNECT_IDENTIFIER:变量_CONNECT_IDENTIFIER 包含用于启动SQL Plus 的连接标识符。 例如,如果 SQL Plus 连接字符串是“hr/my_password@MYSID”,则该变量包含 MYSID。 如果您使用完整的 Oracle Net 连接字符串,例如“hr/my_password@(DESCRIPTION=(ADDRESS_LIST=…(SERVICE_NAME=MYSID.MYDOMAIN)))”,则 _CONNECT_IDENTIFIER 将设置为 MYSID。 如果未明确指定连接标识符,则 _CONNECT_IDENTIFIER 包含 Oracle 用于连接的默认连接标识符。 例如,在 UNIX 上,它将包含环境变量 TWO_TASK 或 ORACLE_SID 中的值。 如果未连接 SQL Plus,则该变量被定义为空字符串。
    • _DATE:变量_DATE 可以是动态的,显示当前日期,也可以设置为固定字符串。 日期使用 NLS_DATE_FORMAT 的值进行格式化,并可能显示时间信息。 默认情况下,使用 &_DATE 的 DEFINE 或取消引用将给出使用时的日期。 _DATE 可以是 UNDEFINED,或使用显式 DEFINE 命令设置为固定字符串。 通过将 _DATE 定义为空字符串来重新启用动态日期行为。
    • _EDITOR:变量 _EDITOR 包含外部文本编辑器可执行文件名。
    • _O_RELEASE:变量_O_RELEASE 包含Oracle 数据库版本号的字符串表示。 如果您的 Oracle 数据库版本是 9.2.0.3.0,则该变量包含“902000300”。 如果您使用 Oracle Net 连接到远程数据库,Oracle 版本可能与 SQL*Plus 版本不同。
    • _O_VERSION:变量 _O_VERSION 包含一个显示数据库版本和可用选项的文本字符串。
    • _SQLPLUS_RELEASE:变量_SQLPLUS_RELEASE 包含格式与_O_RELEASE 类似的SQL*Plus 版本号。
    • _USER:变量 _USER 包含 SHOW USER 给出的当前用户名。 如果未连接 SQL*Plus,则该变量定义为空字符串。
    • _SQL_ID:SQL ID 是标识用于数据库监控的 SQL 语句的唯一值。 SQL ID 将分配给预定义的 SQL*Plus 变量 _SQL_ID。

    2.7 脚本参数

    假设我们有如下的脚本:

    $ cat test.sql
    SET VERIFY OFF
    select '&1' from dual;
    exit
    
    • 1
    • 2
    • 3
    • 4

    我们可以以以下方式调用:

    -- 在操作系统调用
    $ sqlplus -S / as sysdba @test King
    
    'KIN
    ----
    King
    
    -- 在SQL Plus中调用
    SQL> @test King
    
    'KIN
    ----
    King
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    脚本参数成为定义的替换变量。 第一个参数的变量名是“1”,第二个是“2”,以此类推。效果与在SQL Plus中输入以下相同:

    SQL> define 1 = King
    SQL> @test
    
    'KIN
    ----
    King
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    脚本参数变量的类型为 CHAR,类似于使用 DEFINE 显式创建的变量。

    允许使用单引号或双引号引用参数。 这允许在参数中使用空格。 调用 SQLPlus 的操作系统和脚本语言以不同的方式处理引号。 它们可能会也可能不会将引号传递给 SQLPlus 可执行文件。 例如,在 UNIX 上的标准 Bourne shell 中,参数周围的引号在参数传递给 SQLPlus 之前被去除,而 SQLPlus 永远不会看到引号。

    建议使用您的 SQL*Plus 补丁级别检查引用参数在您的操作系统上是如何处理的。 为了 UNIX 和 Windows 环境之间的可移植性,在包含空格的参数周围使用双引号

    例如:

    $ sqlplus -S / as sysdba @test "King Queue"
    
    'KINGQUEUE
    ----------
    King Queue
    
    $ sqlplus -S / as sysdba @test ""
    
    '
    -
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    简而言之,目前还没有方法将引号作为参数传递。

    2.8 更多关于替代变量

    替换变量引用在命令被解析和执行之前被预处理和替换。 伪代码如下:

    1. Loop for each "&" and "&&" variable reference:
        If the variable already has a value defined (i.e. stored)
            Replace the variable reference with the value
        else
            Prompt for a value
            Replace the variable reference with the value
            If the variable is prefixed with "&&" then
                define (i.e. store) the variable for future use
    
    2. Execute the statement
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    第 1 步发生在 SQL Plus 客户端工具中。 SQL Plus 然后将最后的语句发送到执行步骤 2 的数据库引擎。

    不能在 PL/SQL 循环中重复提示。 此示例提示一次,输入的值将替换为脚本文本。 然后将生成的脚本发送到数据库引擎执行。 相同的输入值在表中存储五次:

    SQL> create table mytable (a int);
    
    Table created.
    
    begin
      for i in 1 .. 5 loop
        insert into mytable values (&myv);
      3    4    end loop;
      5  end;
      6  /
    Enter value for myv: 1
    old   3:     insert into mytable values (&myv);
    new   3:     insert into mytable values (1);
    
    PL/SQL procedure successfully completed.
    
    SQL> select count(*) from mytable;
    
      COUNT(*)
    ----------
             5
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21

    替代变量不会递归展开。 如果引用变量的值包含一个 & 符号,则该 & 符号按字面意思使用,不被视为第二个变量前缀:

    set escape \
    define myv = \&mytext
    prompt &myv
    -- 输出为:
    &mytext
    
    • 1
    • 2
    • 3
    • 4
    • 5

    您不能将替换变量用作命令的第一个标记。 每个命令名称必须是硬编码文本,否则会显示错误。

    SQL> &myv * from dual;
    SP2-0734: unknown command beginning "&myv * fro..." - rest of line ignored.
    
    • 1
    • 2

    替代变量不能用于 APPEND、CHANGE、DEL 和 INPUT 等缓冲区编辑命令。 这些命令中的与号 (&) 按字面意思处理。

    如果您希望在替换变量名之后立即使用字母数字字符,请将 SET CONCAT 的值(默认为句点 (.))将变量名与以下字符分开。例如:

    SQL> spool &mycity.Australia.log
    -- 等效于
    SQL> spool MelbourneAustralia.log
    
    SQL> spool &myfile..log
    -- 等效于
    SQL> spool reports.log
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    ANSI“/* */”或“–”注释中看起来像替换变量的文本可能被视为一个,例如:

    SQL> set feedback only
    SQL> select department_id, location_id /* get dept & loc */ from departments;
    Enter value for loc: test
    old   1: select department_id, location_id /* get dept & loc */ from departments
    new   1: select department_id, location_id /* get dept test */ from departments
    
    27 rows selected.
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    &和loc之间居然可以有空格,不过还是建议写为&loc。

    3 使用绑定变量

    绑定变量在 SQL 和 PL/SQL 语句中用于保存数据或结果集。 它们通常用于 SQL 语句中以优化语句性能。 带有绑定变量的语句可以多次重新执行,而无需重新解析。 它们的值可以在 PL/SQL 块中设置和引用。 它们可以在 SQL 语句中引用,例如 选择。 除 VARIABLE 和 PRINT 命令外,绑定变量引用应以冒号为前缀。

    绑定变量是使用 VARIABLE 命令创建的。 以下 PL/SQL 块设置绑定变量:

    variable bv number
    begin
      :bv := 8;
    end;
    /
    
    -- 或者
    variable bv number
    execute :bv := 8
    
    -- 或者
    variable bv number = 8
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    显示变量定义和值:

    SQL> variable
    variable   bv
    datatype   NUMBER
    SQL> print bv
    
            BV
    ----------
             8
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    还可以作为参数传递给SQL Plus命令,仅支持EXIT:

    SQL> EXIT :bv
    Disconnected from Oracle Database 21c Enterprise Edition Release 21.0.0.0.0 - Production
    Version 21.3.0.0.0
    [oracle@oracle-21c-vagrant ~]$ echo $?
    8
    
    • 1
    • 2
    • 3
    • 4
    • 5

    无法取消定义或删除 SQLPlus 会话中的绑定变量。 但是,退出 SQLPlus 时不会记住绑定变量。

    有关自动显示值和对整个结果集使用 REFCURSOR 绑定变量的信息,请参阅 SQL*Plus 用户指南和参考手册中的关于使用绑定变量和 VARIABLE。

    3.1 将替换变量分配给绑定变量

    您可以将替换变量分配给绑定变量:

    define mysubv = 123
    variable mybndv number
    execute :mybndv := &mysubv;
    SQL> print mybndv
    
        MYBNDV
    ----------
           123
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    SQL*Plus 在替换“mysubv”的值后执行 PL/SQL 赋值语句。 如果尚未定义“mysubv”,系统会提示您输入值。

    绑定变量可用于后续 SQL 或 PL/SQL 命令。

    3.2 将绑定变量分配给替换变量

    有时,使绑定变量的值可用于 SQL*Plus 命令(如 TTITLE 或 SPOOL)很有用。 例如,您可能想要调用一个返回字符串的 PL/SQL 函数并将该值用作 SQL Plus 假脱机文件名。 SPOOL 命令不理解绑定变量语法,因此需要先将绑定变量值分配给替换变量。

    示例:

    variable mybv varchar2(14)
    begin
      /* ... */
      :mybv := 'report.log';
    end;
    /
    
    column mybvcol new_value nv noprint
    -- 使用查询将绑定变量的值传递给新的替换变量“nv”:
    -- 以下命令不会产生输出
    select :mybv mybvcol from dual;
    
    SQL> define nv
    DEFINE NV              = "report.log" (CHAR)
    
    spool &nv
    spool off
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17

    4 使用系统变量

    大多数系统变量是用于控制 SQLPlus 系统行为的 SET 命令选项。 例如,要从 SQLPlus 设置输出行大小:

    set linesize 60
    
    • 1

    每个系统变量的当前状态可以用 SHOW 命令显示。

    SQL> show linesize
    linesize 80
    
    • 1
    • 2

    系统变量有时称为 SET 变量。

    某些系统变量包含无法设置的值。 例如,RELEASE(SQL*Plus 版本的字符串表示)只能显示。

    4.1 影响替代变量的系统变量

    几个系统变量影响替代变量。

    4.1.1 SET CONCAT

    使用 SET CONCAT 定义将替换变量的名称与紧跟在变量名称后面的字母数字字符分开的字符。 默认情况下,它是单个句点 (.)。

    例如,如果“mycity”被定义为“Melbourne”,那么以下命令是等价的:

    SQL> spool &mycity.Australia.log
    SQL> spool MelbourneAustralia.log
    
    • 1
    • 2

    4.1.2 SET DEFINE

    使用 SET DEFINE OFF 停止 SQLPlus 执行任何变量替换。 这使得 SQLPlus 将所有与号 (&) 视为文字字符,并防止 SQL*Plus 提示您输入值:

    SQL> set define off
    SQL> select 'B&W' MyHeading from dual;
    
    MYH
    ---
    B&W
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    默认的替换变量前缀是一个 & 符号。 SET DEFINE 命令可用于更改变量名前缀字符。 SET DEFINE ON 重新打开变量替换并将前缀字符重置为“&”

    4.1.3 SET ESCAPE

    使用 SET ESCAPE 防止孤立出现的“&”被视为替换变量前缀:

    SQL> show escape
    escape OFF
    SQL> select 'B\&W' MyHeading from dual;
    Enter value for w: w
    old   1: select 'B\&W' MyHeading from dual
    new   1: select 'B\w' MyHeading from dual
    
    MYH
    ---
    B\w
    
    SQL> set escape \
    SQL> select 'B\&W' MyHeading from dual;
    
    MYH
    ---
    B&W
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17

    任何没有转义字符的“&”都被视为变量前缀。

    4.1.4 SET NULL

    SET NULL 设置打印 NULL 数据值时 SQL*Plus 显示的文本。

    如果 COLUMN NEW_VALUE(或 COLUMN OLD_VALUE)命令将变量与选定列相关联并且当前行包含 NULL 值,则替换变量可以采用 SET NULL 文本的值。 替换变量的类型在包含 NULL 时临时更改为 CHAR。

    SQL> show null
    null ""
    SQL> select null from dual;
    
    N
    -
    
    
    SQL> set null A
    SQL> select null from dual;
    
    N
    -
    A
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    4.1.5 SET NUMFORMAT

    SET NUMFORMAT 和 SET NUMWIDTH 交互。 使用 SET NUMFORMAT 更改数值变量的默认显示格式。 使用 SET NUMFORMAT “” 删除格式。 当没有格式时,默认数字格式使用 SET NUMWIDTH 选项:

    SQL> variable bv number = 123.45
    SQL> show numformat
    numformat ""
    SQL> print bv
    
            BV
    ----------
        123.45
    
    SQL> set numformat 0999.9
    SQL> print bv
    
         BV
    -------
     0123.5
    
    SQL> set numformat 9.9EEEE
    SQL> print bv
    
           BV
    ---------
      1.2E+02
    
    SQL> set numformat ""
    SQL> print bv
    
            BV
    ----------
        123.45
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29

    4.1.6 SET NUMWIDTH

    只有当 SET NUMFORMAT 没有值时,SQL*Plus 才使用 SET NUMWIDTH 的值。 使用 SET NUMWIDTH 改变数值变量的显示宽度:

    SQL> show numformat
    numformat ""
    SQL> show numwidth
    numwidth 10
    SQL> variable bv number = 123.45
    SQL> print bv
    
            BV
    ----------
        123.45
    
    SQL> set numwidth 20
    SQL> print bv
    
                      BV
    --------------------
                  123.45
    SQL> set numwidth 4
    SQL> print bv
    
      BV
    ----
     123
    
    SQL> set numwidth 2
    SQL> print bv
    
    BV
    --
    ##
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30

    请注意,该值在字段宽度内是右对齐的,并且每个示例中前导空格的数量都会发生变化。

    如果数字替换变量的格式或字段宽度对于值来说太小,SQL*Plus 会显示井号 (#)。

    4.1.7 SET SQLPROMPT

    在 SQL*Plus 10g 中,每次打印提示时都会动态替换提示中的替换变量。 与 TTITLE 中使用的变量一样,它们不应以 ‘&’ 为前缀,否则它们仅在执行 SET SQLPROMPT 命令时被替换一次。

    在提示中使用预定义的替换变量 _USER 和 _CONNECT_IDENTIFIER 来提供当前用户名和数据库:

    $ sqlplus hr/Welcome1@orclpdb1
    SQL> set sqlprompt "_user'@'_connect_identifier:SQL> "
    HR@orclpdb1:SQL> connect oe/Welcome1@orclpdb1
    Connected.
    OE@orclpdb1:SQL> connect / as sysdba
    Connected.
    SYS@ORCLCDB:SQL> define
    DEFINE _DATE           = "23-JUN-22" (CHAR)
    DEFINE _CONNECT_IDENTIFIER = "ORCLCDB" (CHAR)
    DEFINE _USER           = "SYS" (CHAR)
    DEFINE _PRIVILEGE      = "AS SYSDBA" (CHAR)
    DEFINE _SQLPLUS_RELEASE = "2103000000" (CHAR)
    DEFINE _EDITOR         = "vi" (CHAR)
    DEFINE _O_VERSION      = "Oracle Database 21c Enterprise Edition Release 21.0.0.0.0 - Production
    Version 21.3.0.0.0" (CHAR)
    DEFINE _O_RELEASE      = "2103000000" (CHAR)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16

    每次打印提示时,SQL*Plus 都会检查每个单词以查看它是否是已定义的替换变量。 如果是,它将打印其值。 否则会逐字显示。 嵌套引号中的文本永远不会被替换。 出于性能原因,默认提示“SQL>”中的 SQL 一词永远不会被视为替换变量。

    只有当 SET SQLPLUSCOMPATIBILITY 为 10.1 或更高版本时,提示中的变量才会被动态替换。 否则,对于 SQL*Plus 版本 9.2 和更早版本,在执行 SET SQLPROMPT 命令时,可以替换一次以“&”为前缀的变量。

    4.1.8 SET VERIFY

    使用 SET VERIFY 来控制 SQL*Plus 在替换变量值时是否回显新旧语句文本。 SET VERIFY 仅对 SQL 和 PL/SQL 语句中使用的替换变量有影响:

    SQL> show verify
    verify ON
    SQL> select '&v' from dual;
    Enter value for v: aaa
    old   1: select '&v' from dual
    new   1: select 'aaa' from dual
    
    'AA
    ---
    aaa
    
    SQL> set verify off
    SQL> select '&v' from dual;
    Enter value for v: aaa
    
    'AA
    ---
    aaa
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18

    SQL*Plus 命令(如 SET , PROMPT, TTITLE)中使用的变量不会验证。

    4.2 Titles 和 EXIT 中的系统变量

    在 TTITLE、BTITLE、REPHEADER、REPFOOTER 和 EXIT 命令中引用系统变量有一种特殊的语法。 每个特殊变量的名称与以“SQL.”为前缀的 SHOW 选项相同。

    可以引用的特殊变量包括:

    • SQL.PNO - 页码
    • SQL.LNO - 行号
    • SQL.USER - 当前用户名
    • SQL.RELEASE - SQL*Plus 版本
    • SQL.SQLCODE - 最后一个 Oracle “ORA” 错误号

    例如:

    ttitle left 'Salary Report. Page: ' sql.pno
    select salary from employees;
    exit sql.sqlcode
    
    • 1
    • 2
    • 3

    数字类型的系统变量,例如 SQL.SQLCODE 使用与数字替换变量相同的规则进行格式化。

    变量不能以“&”为前缀

    这些变量不是替代变量。 DEFINE 命令不显示它们(可以用show命令显示)。 它们不能在一般命令中引用。 如果您创建具有相同名称的替换变量,系统变量不会受到影响。 例如,如果您创建一个名为 USER 的替换变量,则 SQL.USER 不会受到影响。 如果更改了预定义的替换变量 _O_RELEASE,系统变量 SQL.RELEASE 不会受到影响。

    5 SQL*Plus 替换变量命令

    替换变量可用于替换几乎所有 SQL*Plus 命令中的选项和值。 有几个命令对替换变量具有特殊意义。 这些将在下面讨论。

    5.1 ACCEPT 命令

    ACCEPT 命令总是提示输入变量的值,创建新变量或替换现有变量。 ACCEPT 优于导致提示的双与号 (&&) 变量引用。 ACCEPT 允许自定义提示文本并允许指定默认值。 ACCEPT 进行类型和格式检查。

    SQL> accept myv number default 10 prompt 'Enter a number: '
    Enter a number: 12345
    SQL> define myv
    DEFINE MYV             =      12345 (NUMBER)
    
    SQL> accept myv number default 10 prompt 'Enter a number: '
    Enter a number: a1
    SP2-0425: "a1" is not a valid NUMBER
    Enter a number:
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    accept比define强大,可以定义数据类型,可以进行类型检查,而define只能定义CHAR型。

    ACCEPT 命令可以理解数字、字符串和日期。 如果使用 FORMAT 子句,SQL*Plus 会根据给定格式验证输入。 如果输入无效,系统会重新提示您输入值。

    如果将诸如“A10”之类的 FORMAT 说明符用于 CHAR 变量,则输入的值可以是最多 10 个字符(包括 10 个字符)的任何长度。

    如果将 FORMAT 说明符用于 NUMBER 类型,则允许的输入取决于使用的说明符。 例如,“9EEEE”(指数表示法)的说明符允许“3e2”,但不允许“300”或“12e2”。 格式说明符“999.99”允许输入“123.45”和“67”。

    DATE 变量根据明确提供的 FORMAT 或默认会话日期格式(如“DD-MON-YYYY”)进行验证。

    在针对格式模型成功验证后,变量将存储在适当的变量类型中。

    ACCEPT … HIDE 选项可用于防止您输入的值显示在屏幕上。 这对于需要提示输入密码的脚本很有用。 请注意,某些操作系统无法将批处理程序脚本输出重定向到 ACCEPT … HIDE 命令。

    SQL> accept myv hide number default 10 prompt 'Enter a number: '
    Enter a number: ***
    
    • 1
    • 2

    默认日期格式获取:

    select VALUE from NLS_SESSION_PARAMETERS where PARAMETER = 'NLS_DATE_FORMAT'
    VALUE
    --------------------------------------------------------------------------------
    DD-MON-RR
    
    SQL> accept myv date prompt 'Enter a date: '
    Enter a date: 23-JUN-22
    SQL> define myv
    DEFINE MYV             = "23-JUN-22" (CHAR)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    5.2 COLUMN 命令

    COLUMN NEW_VALUE 和 COLUMN OLD_VALUE 命令可用于将替换变量与 SELECT 列的数据相关联。

    当列“ dectmence_id”选择时,一个替换变量“ DNV”会被创建以依次保存列的每一行。查询完成后变量保持定义:

    column department_id new_value dnv
    select department_id from departments where department_id between 60 and 100;
    define dnv
    
    • 1
    • 2
    • 3

    输出为:

    DEPARTMENT_ID
    -------------
               60
               70
               80
               90
              100
    
    DEFINE DNV             =        100 (NUMBER)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    COLUMN OLD_VALUE 和 NEW_VALUE 替换变量可用于基本的数字和文本列类型。 它们用于执行与 COLUMN 命令具有相同名称的列的任何查询。 它们的当前值可以在查询执行期间显示在报告标题和页眉页脚中。

    COLUMN NEW_VALUE 变量应在页面开头的 TTITLE 和 REPHEADER 标题中使用。 它们保存即将在页面上打印的新行中的数据。 查询完成后,变量具有最后一行的值。

    COLUMN OLD_VALUE 变量用于页面末尾的 BTITLE 和 REPFOOTER 标题。 它们包含页面上最近打印的旧行的数据。

    变量根据需要更改类型。 如果运行具有相同列名的另一个查询,则该变量可能采用新类型。 此外,如果数字列包含空值,则该列上的替换变量从类型 NUMBER 更改为该行的 CHAR。 这使它可以保存 SET NULL 选项的当前字符串。 当获取下一个数值时,变量变回 NUMBER。

    如果查询未选择任何行,并且替换变量不存在,则创建零长度 CHAR 变量。 如果替换变量存在,那么它的值和类型不会改变。

    与 ACCEPT 命令的 DATE 选项类似,DATE 列上的变量存储为 CHAR 类型。

    COLUMN NEW_VALUE 和 OLD_VALUE 可用于将值从绑定变量传输到替换变量。

    5.3 DEFINE 命令

    使用 DEFINE 命令显式创建和显示替换变量:

    SQL> define myv = 'King'
    SQL> define myv
    DEFINE MYV             = "King" (CHAR)
    
    • 1
    • 2
    • 3

    使用不带参数的 DEFINE 会列出所有已定义的替换变量。 DEFINE 列出的任何变量都被称为已定义。

    可以通过使用不同的值重复 DEFINE 命令来重新定义变量。

    DEFINE 命令只创建类型为 CHAR 的变量。

    5.4 EDIT 命令

    EDIT 命令启动外部编辑器,例如记事本或 Vi。 在大多数操作系统上,SQL*Plus 有一个名为 _EDITOR 的预定义替换变量设置为默认编辑器的可执行文件:

    SQL> define _editor
    DEFINE _EDITOR         = "vi" (CHAR)
    
    • 1
    • 2

    EDIT 可以编辑命名文件。 它还可以编辑当前的 SQL 缓冲区(保存最近执行的 SQL 语句)。 当外部编辑器关闭时,更改的语句被加载回 SQL 缓冲区。 EDIT 将 SQL 缓冲区写入名为 afiedt.buf 的临时文件。 可以使用 SET EDITFILE 命令更改临时文件名。

    您可以将 _EDITOR 替换变量的值重新定义为任何编辑器。

    创建 SQL*Plus 脚本的推荐方法是为 EDIT 显式指定文件名,然后使用 START 或“@”命令运行该文件。

    edit test.sql
    
    • 1

    5.5 EXIT 命令

    在许多操作系统上,EXIT 命令可以将数值绑定变量或替换变量的值传递给操作系统环境。 在 UNIX 上,可以使用命令“echo $?”显示 SQL*Plus 的返回状态。 在 Bourne、Korn 和 Bash shell 中,或者在 C shell 中使用“echo $status”。

    要返回替换变量,建议不要在其名称前使用 & 前缀。 如果使用“&”或“&&”,命令预处理器会在最终解析和执行 EXIT 命令之前使用默认数字格式规则(参见 6.3 替换变量格式)进行替换。 这是命令中数字替换变量的正常预处理。 由于 Oracle 格式说明符可能包含不是数字的小数和组分隔符,或者数字可能会溢出格式并被替换为井号 (#),因此从生成的格式化字符串到操作系统的最终转换可能会出现问题 返回状态。 例如,如果格式化规则返回指数格式,数字被格式化为“4E+05”,那么EXIT命令只返回值“4”给操作系统。

    当“&”不作为替换变量名的前缀时,例如 “EXIT myv”,SQL*Plus 内部使用更实用的格式说明符“9999999990”将内部数字格式转换为用作 EXIT 命令参数的字符串。

    请注意,某些操作系统会限制可以从程序返回的数字范围。 在此类系统上,返回值可能会溢出并包含意外数字。 这通常会限制包含最后一个 Oracle 错误号的系统变量 SQL.SQLCODE 的使用。 通常,此数字大于操作系统支持的退出返回状态。

    如果在 EXIT 语句中引用了非数值变量,则 EXIT 命令退出但报告错误。 操作系统返回值与 EXIT FAILURE 相同。

    SQLPlus 退出时不保存替换变量。 下次启动 SQLPlus 时,只定义预定义的替换变量和站点和用户配置文件(例如 glogin.sql 和 login.sql)中设置的任何变量。

    5.6 HOST 命令

    HOST 命令运行指定的操作系统命令或打开命令窗口。 在某些操作系统上,像“!”这样的字符 或“$”是 HOST 的同义词。

    在 HOST 命令完成后,将定义替换变量 _RC。 它的值是特定于端口的,并且可能包含文本消息。 在 UNIX 上,如果命令成功则定义为“0”,否则定义为“1”。 也可能是宿主程序返回的运行退出状态。 在其他平台上,_RC 的值没有明确定义,不应依赖它的值。

    SQL> host pwd
    /home/oracle
    
    SQL> define _rc
    DEFINE _RC             = "0" (CHAR)
    SQL> host lll
    /bin/bash: lll: command not found
    
    SQL> define _rc
    DEFINE _RC             = "127" (CHAR)
    SQL> host
    [oracle@oracle-21c-vagrant ~]$ pwd
    /home/oracle
    [oracle@oracle-21c-vagrant ~]$ exit
    exit
    
    SQL>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17

    5.7 TTITLE, BTITLE, REPHEADER 和 REPFOOTER 命令

    报表标题中使用变量来使每个页面与该页面上的数据相关,例如给出报表页面描述的产品项目。 任何替换变量都可以在标题命令中使用。 但是,COLUMN NEW_VALUE 或 OLD_VALUE 命令通常用于将变量与报表查询中的列值相关联。

    在 TTITLE 和 REPHEADER 命令中使用 NEW_VALUE 变量。 在 BTITLE 和 REPFOOTER 命令中使用 OLD_VALUE 变量。 例如,脚本:

    column last_name new_value ttnv old_value btov
    ttitle left 'First employee is: ' ttnv
    btitle left 'Last employee is: ' btov
    select last_name from employees where department_id = 60 order by last_name;
    
    First employee is: Austin
    LAST_NAME
    -------------------------
    Austin
    Ernst
    Hunold
    Lorentz
    Pataballa
    
    
    
    
    Last employee is: Pataballa
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18

    5.7.1 使用带有标题变量的“&”前缀

    标题命令(TTITLE、BTITLE、REPHEADER 和 REPFOOTER)以不同于大多数其他命令的方式替换变量。 (EXIT 和 SET SQLPROMPT 命令除外,它们与标题命令类似)。 通常,您不需要也不会希望在标题命令中的变量名之前放置“&”前缀。 例如,如果您的 TTITLE 命令是:

    ttitle left 'Urgent: ' &2 ' Days High: ' &days
    
    • 1

    您可能应该将其更改为:

    ttitle left 'Urgent: ' 2 ' Days High: ' days
    
    • 1

    标题中变量的准则是:

    如果您希望在每一页上打印相同的变量值,请使用“&”前缀并将变量放在带引号的字符串中:

    accept mycustomer char prompt 'Enter your company name: '
    ttitle left 'Report generated for company &mycustomer'
    select last_name, job_id from employees order by job_id;
    
    • 1
    • 2
    • 3

    如果您希望每个标题的查询数据对每个报告页面都是唯一的,则不要对变量使用“&”前缀,也不要将变量放在引号内。

    column job_id new_value ji_nv noprint
    break on job_id skip page
    ttitle left 'Employees in job: ' ji_nv
    select last_name, job_id from employees order by job_id;
    
    • 1
    • 2
    • 3
    • 4

    SQL*Plus 替换变量在每个命令执行之前展开。 在标题命令中发生这种情况后,生成的字符串将存储为标题文本。 标题中变量的特别之处在于它们需要重新替换为每一页的查询结果。 这样当前的 COLUMN NEW_VALUE 和 OLD_VALUE 替换变量值就会显示在每个页面上,从而为其页面上显示的结果自定义每个标题。 如果无意或错误地使用“&”作为标题变量的前缀,则可能会出现双重替换。 这取决于变量的值,并且在您编写脚本时很容易被忽略。

    打印页面时检查标题中任何未引用的非关键字,以查看它是否为变量。 如果是,则打印其值。 如果不是,则逐字打印该单词。 这意味着如果您在标题命令中使用“&myvar”,并且替换它的文本本身可以解释为另一个变量名称,那么您将获得双重变量替换。 例如,脚本:

    define myvar = scottsvar
    ttitle left &myvar
    define scottsvar = Hello
    select * from dual;
    
    • 1
    • 2
    • 3
    • 4

    导致文本“left scottsvar”被存储为标题。 当标题打印在查询的每一页上时,这个字符串会被重新计算。 标题中的单词“scottsvar”本身被视为变量引用并被替换。 查询输出为:

    Hello
    D
    -
    deX
    
    • 1
    • 2
    • 3
    • 4

    在标题中使用“&”通常会导致 SQL*Plus 脚本参数的数字变量名称出现问题。 如果任意以“&”为前缀的标题变量的值与脚本参数变量名称相同,则将发生双重替换。

    要在标题中显示“&”,请在其前面加上 SET ESCAPE 字符。 与号 (&) 存储为标题文本,并且在打印页面标题时不会被替换。

    5.7.2 标题中的变量和文本间距

    标题中未加引号的空格被删除。 使用空格而不是 SET CONCAT 字符将变量与应该紧邻出现的文本分开。 在引号内使用空格来显示空格。 例如,脚本:

    define myvar = 'ABC'
    ttitle left myvar myvar Text ' Other words'
    select * from dual;
    
    ABCABCText Other words
    D
    -
    X
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    5.8 UNDEFINE 命令

    使用 UNDEFINE 删除已定义的替换变量:

    SQL> undefine myv
    SQL> define myv
    SP2-0135: symbol myv is UNDEFINED
    
    • 1
    • 2
    • 3

    DEFINE 未列出的任何变量都被称为未定义的。

    取消定义未使用的替换变量可能有助于提高 SQLPlus 性能,因为 SQLPlus 可以更快地查找变量。 在 SQLPROMPT 中使用变量时尤其如此。

    5.9 WHENEVER 命令

    WHENEVER OSERROR EXIT 或 WHENEVER SQLERROR EXIT 命令中用于返回状态的替换变量遵循与 EXIT 命令中的变量相同的一般准则。 具体来说,不需要和号 (&) 前缀,例如:

    SQL> whenever sqlerror exit myv
    
    • 1

    请注意在 WHENEVER … EXIT 命令中为替换变量使用与号 (&) 前缀。 使用 & 符号会导致使用 WHENEVER 命令运行时变量的当前值,而不是程序稍后退出时生效的值。 例如,在脚本中:

    define myv = 5
    whenever sqlerror exit &myv
    define myv = 10
    -- This query should fail
    select * from non_existent_table;
    
    • 1
    • 2
    • 3
    • 4
    • 5

    操作系统返回状态为 5。这是因为 WHENEVER 语句已被预处理并执行,就像您键入:

    whenever sqlerror exit 5
    
    • 1

    但是,如果您删除 & 符号:

    define myv = 5
    whenever sqlerror exit myv
    define myv = 10
    -- This query should fail
    select * from non_existent_table;
    
    • 1
    • 2
    • 3
    • 4
    • 5

    返回状态为“10”,即退出时“myv”的值。

    6 替换变量命名空间、类型、格式和限制

    6.1 替换变量命名空间

    在 SQL*Plus 会话中,替换变量只有一个全局名称空间。 如果您使用 CONNECT 重新连接,或使用“@”运行下标,则所有定义的变量仍可以使用,并且可能被覆盖或未定义。

    当子脚本完成时,它定义或更改的所有替换变量对调用脚本都是可见的。 当使用“@”或 START 执行的下标被赋予脚本参数时,这一点尤其明显。 参数“&1”等被重新定义,父脚本看到新值。

    为了最大限度地减少问题和一般可读性,请对命令参数使用符号变量名称。 所有其他引用应使用新变量名而不是“&1”。 例如:

    define myuser = '&1'
    @myscript.sql King
    -- 以下即myscript.sql 中的SQL
    select first_name from employees where last_name = '&myuser';
    
    • 1
    • 2
    • 3
    • 4

    对 myscript.sql 的调用将“&1”的值更改为“King”。 通过在“myuser”中保存“&1”的原始值并在 SELECT 中使用“&myuser”而不是“&1”,查询可以正确执行。

    6.2 替代变量类型

    SQL*Plus 存储的替换变量类型有:

    • CHAR
    • NUMBER
    • BINARY_FLOAT
    • BINARY_DOUBLE

    CHAR 类型是类似于数据库表 VARCHAR2 列类型的通用文本格式。 通过以下方式创建的变量均为CHAR 类型:

    • DEFINE
    • 来自“&”变量的提示
    • 从脚本参数

    这可确保输入的值被逐字替换而没有转换损失。

    由 COLUMN NEW_VALUE 或 OLD_VALUE 为 Oracle 数字格式的列创建的变量将具有 NUMBER 类型。 这些替换变量存储在 Oracle 的内部数字表示中,就像它们在数据库中一样。 这允许在不损失任何内部价值的情况下更改显示格式。 BINARY_FLOAT 和 BINARY_DOUBLE 类型的替换变量同样为 Oracle BINARY_FLOAT 和 BINARY_DOUBLE 列创建。 这些变量存储在本机机器表示中。 CHAR 类型用于 NEW_VALUE 和 OLD_VALUE 变量以及所有其他列类型。

    没有明确的 DATE 类型。 ACCEPT 命令中的 DATE 关键字仅用于允许对日期格式进行正确的格式验证。 由 ACCEPT … DATE 或 COLUMN NEW_VALUE 在日期列上创建的替换变量存储为 CHAR 类型。 例如:

    SQL> accept mydvar date format 'DD-MON-YYYY'
    09-JAN-2022
    SQL> define mydvar
    DEFINE MYDVAR          = "09-JAN-2022" (CHAR)
    
    • 1
    • 2
    • 3
    • 4

    如果变量已经存在并被重新定义,则丢弃其旧类型并使用新类型。

    替换变量的类型通常是透明的。 替代变量是弱类型的。 例如,COLUMN NEW_VALUE 变量在每个新查询中采用指定列的特定类型。 它也可能在查询期间更改类型。 例如,当获取 NULL 值时,用于 NUMBER 列的替换变量的类型从 NUMBER 更改为 CHAR。 当获取下一个数值时,它会变回 NUMBER。

    因为没有变量的直接比较,所以没有为任何类型定义类型比较语义。 在执行任何可以进行比较的 SQL 或 PL/SQL 语句之前,所有变量都被文本替换。

    6.3 替换变量格式

    当一个变量被替换,或者它的值由一个 DEFINE 命令显示时,它在最终执行引用该变量的命令之前被格式化为文本。

    CHAR 变量被逐字替换。

    NUMBER 变量根据 SET NUMWIDTH(默认)或 SET NUMFORMAT(如果您已明确设置)进行格式化。

    即使在创建变量之后,也可以更改数字的显示格式。 为了显示这一点,首先创建一个 NUMBER 变量。 您不能使用 DEFINE 来执行此操作,因为它使所有新变量的类型为 CHAR。 而是使用从 NUMBER 列继承 NUMBER 类型的 COLUMN NEW_VALUE 命令:

    column c2 new_val m
    select 1.1 c2 from dual C2;
    SQL> define m
    DEFINE M               =        1.1 (NUMBER)
    
    • 1
    • 2
    • 3
    • 4

    更改格式会影响数字的显示,但不会影响存储的值:

    SQL> set numformat 99.990
    SQL> define m
    DEFINE M               =   1.100 (NUMBER)
    
    • 1
    • 2
    • 3

    6.4 替代变量限制

    允许的最大替换变量数为 2048。SQLPlus 给出一个错误,尝试创建更多。 该限制包括预定义的变量,但是如果需要,这些变量可以是未定义的。 留下大量不必要定义的变量会降低 SQLPlus 的性能,因为变量查找速度较慢。

    字符替换变量最长可达 240 个字节。

    数字替换变量包含所有 Oracle 数字。 请参阅 Oracle 数据库 SQL 语言参考中的 NUMBER 数据类型。

    当命令行进行变量替换时,生成的行长度不能超过:

    • 如果是一行 SQL(如 SELECT 或 INSERT)或 PL/SQL 文本(如 BEGIN 或 CREATE PROCEDURE),则为 3000 字节
    • 如果是 SQL*Plus 命令的一行(如 TTITLE 或 COLUMN),则为 2499 字节

    否则会显示错误。

    这些限制在旧版本的 SQL*Plus 中可能更低。

    7 iSQL*Plus and Substitution Variables

    iSQL*Plus 已经不存在了,所以这一节跳过。

    8 替代变量摘要

    SQL*Plus 替换变量可用于自定义报告,并可用于代替硬编码文本。 替换变量可以与绑定变量和系统变量交互。 具有存储值的替换变量被称为已定义。

    替换变量可以显式定义:

    • 通过 ACCEPT
    • 通过 DEFINE
    • 通过将参数传递给 SQL*Plus 脚本

    替换变量可以隐式定义:

    • 使用 COLUMN NEW_VALUE 或 COLUMN OLD_VALUE 命令
    • 通过在未定义的变量上使用双 && 前缀(没有&前缀,因为其使用完即变为未定义)

    其它:

    • 替换变量引用具有“&”或“&&”前缀。
    • 如果引用了变量但未定义变量,SQL*Plus 将停止并提示输入值。
    • 替换变量引用在命令被解析和执行之前被预处理和替换。
    • 替换变量具有当前类型,例如 CHAR。 替代变量是弱类型的,并根据需要更改类型。
    • 值被替换为文本。 所以即使变量的类型是 NUMBER,它的值也会被格式化为文本字符串,被替换,然后执行命令。
    • 在标题、EXIT 和 SET SQLPROMPT 中,替换变量不必以“&”或“&&”作为前缀。
    • 预定义的替换变量以前导下划线 (_) 命名。 它们可以是未定义的或重新定义的。

    9 替换变量示例

    9.1 设置替换变量的值

    -- 1. DEFINE 命令显式设置
    define myv = 'King'
    
    -- 2. ACCEPT命令提示您输入一个值并创建一个字符变量“myv”设置为您输入的文本。
    accept myv char prompt 'Enter a last name: '
    
    -- 3. 在未定义的变量之前使用“&&”会提示您输入一个值并在语句中使用该值
    select first_name from employees where last_name = '&&myuser';
    
    -- 4. 使用 COLUMN NEW_VALUE 将替换变量设置为存储在数据库中的值
    column last_name new_value mynv
    select last_name from employees where employee_id = 100;
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    9.2 使用替换变量

    一旦替换变量有了值,就可以通过在变量名前加上与号 (&) 来引用它。

    如果变量“myv”已经定义,它可以像这样使用:

    select employee_id from employees where last_name = '&myv';
    
    • 1

    9.3 查找所有已定义的替换变量

    不带参数的 DEFINE 命令显示所有已定义的替换变量、它们的值和它们的类型。 例如:

    SQL> define
    DEFINE _DATE           = "23-JUN-22" (CHAR)
    DEFINE _CONNECT_IDENTIFIER = "orclpdb1" (CHAR)
    DEFINE _USER           = "SSB" (CHAR)
    DEFINE _PRIVILEGE      = "" (CHAR)
    DEFINE _SQLPLUS_RELEASE = "2103000000" (CHAR)
    DEFINE _EDITOR         = "vi" (CHAR)
    DEFINE _O_VERSION      = "Oracle Database 21c Enterprise Edition Release 21.0.0.0.0 - Production
    Version 21.3.0.0.0" (CHAR)
    DEFINE _O_RELEASE      = "2103000000" (CHAR)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    9.4 在没有提示的情况下插入包含“&”的数据

    有两种方法可以使“&”被视为文本而不引起提示。 第一个关闭所有变量替换:

    set define off
    create table mytable (c1 varchar2(20));
    insert into mytable (c1) values ('thick & thin');
    
    • 1
    • 2
    • 3

    第二种方法通过转义,可用于忽略个别出现的“&”,同时允许其他人为替换变量添加前缀:

    set escape \
    create table mytable (c1 varchar2(20));
    insert into mytable (c1) values ('thick \& thin');
    insert into mytable (c1) values ('&mysubvar');
    
    • 1
    • 2
    • 3
    • 4

    此方法中的第一个 INSERT 语句将文本“thick & thin”存储在表中。 第二个 INSERT 使 SQL Plus 提示您输入一个值,然后存储该值。

    9.5 将当前日期放入假脱机文件名

    使用 SYSDATE 您可以查询当前日期并将其放入替换变量中。 然后可以在 SPOOL 命令中使用替换变量:

    column dcol new_value mydate noprint
    select to_char(sysdate,'YYYYMMDD') dcol from dual;
    spool &mydate.report.txt
    
    -- my report goes here
    select last_name from employees;
    
    spool off
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    在此示例中,第一个查询将日期放入替换变量“mydate”中。 由于 COLUMN 命令中的 NOPRINT 选项,此查询没有可见的输出。 在 SPOOL 命令中,第一个句点 (.) 表示变量名称的结尾,并且不包含在结果字符串中。 如果“mydate”包含来自第一个查询的“20030120”,则假脱机文件名将是“20030120report.txt”。

    您可以使用此技术为文件名构建任何字符串。

    句点是 SET CONCAT 的默认值。 如果您分配了另一个字符,则使用它而不是句点来结束替换变量名称。

    9.6 在替换变量之后立即附加字母数字字符

    如果您希望在替换变量之后立即附加字母数字字符,请使用 SET CONCAT 的值将变量名称与以下文本分开。 SET CONCAT 的默认值为单个句点 (.)。 例如:

    -- 创建一个名为“MelbourneAustralia.txt”的文件
    define mycity = Melbourne
    spool &mycity.Australia.txt
    
    • 1
    • 2
    • 3

    9.7 在替换变量后放置句点

    如果 SET CONCAT 是句点 (.) 并且您想在替换变量后立即附加句点,则一起使用两个句点。 例如:

    -- 相对于spool Melbourne.log
    define mycity = Melbourne
    spool &mycity..log
    
    • 1
    • 2
    • 3

    9.8 在 TITLE、TITLE、REPHEADER 或 REPFOOTER 中使用固定值变量

    此示例使报表的每一页都具有完全相同的标题。 它可用于 TTITLE、BTITLE、REPHEADER 或 REPFOOTER 命令。

    在 TTITLE 命令中,在变量名“dept”前加上“&”并将其放在带引号的字符串中:

    define dept = '60'
    ttitle left 'Salaries for department &dept'
    select last_name, salary from employees where department_id = &dept;
    
    • 1
    • 2
    • 3

    9.9 在 TITLE、TITLE、REPHEADER 或 REPFOOTER 中使用更改值变量

    此示例在报告的每一页上使用不同的标题。 每个标题都包含一个从该特定页面上显示的查询结果派生的值。

    在 TTITLE 命令中,不要在变量名“dv”之前放置“&”。 将变量名放在带引号的字符串之外:

    column department_id new_value dv noprint
    ttitle left 'Members of department ' dv
    break on department_id skip page
    select department_id, last_name from employees order by department_id, last_name;
    
    • 1
    • 2
    • 3
    • 4

    在 BTITLE 或 REPFOOTER 命令中,使用 COLUMN OLD_VALUE 变量而不是 COLUMN NEW_VALUE 变量。

    9.10 在 SPOOL 等 SQL*Plus 命令中使用绑定变量的值

    如果要在 SQL*Plus 命令中使用绑定变量的值,必须首先将其复制到替换变量。

    SPOOL、SET 和 TTITLE 等 SQL*Plus 命令在 SQL Plus 程序中执行,不会传递到数据库执行。 因此,他们不理解绑定变量。

    要将绑定变量的值用作假脱机文件的名称:

    -- Set a bind variable to a text string
    variable mybindvar varchar2(20)
    begin
      :mybindvar := 'myspoolfilename';
    end;
    
    -- Transfer the value from the bind variable to the substitution variable
    column mc new_value mysubvar noprint
    -- 这个select是关键
    select :mybindvar mc from dual;
    
    -- Use the substitution variable
    spool &mysubvar..txt
    select * from employees;
    
    spool off
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16

    9.11 将参数传递给 SQL*Plus 替换变量

    您可以在命令行上将参数传递给 SQL*Plus 脚本:

    sqlplus hr/my_password @myscript employees "De Haan"
    
    • 1

    可以使用“&1”和“&2”在脚本中引用它们。 例如,myscript.sql 可以是:

    set verify off
    select employee_id from &1 where last_name = '&2';
    
    • 1
    • 2

    这里的“SET VERIFY OFF”命令阻止 SQL*Plus 在变量被替换之前和之后回显 SQL 语句。 该查询从“employees”表中返回员工“De Haan”的员工标识符。

    参数也可以传递给在 SQL Plus 中调用的脚本:

    SQL> @myscript.sql employees "De Haan"
    
    • 1

    9.12 将操作系统变量传递给 SQL*Plus

    您可以将操作系统变量作为命令行参数传递给 SQL*Plus 脚本。 例如,在 UNIX 上:

    sqlplus hr/my_password @myscript.sql $USER
    
    • 1

    脚本 myscript.sql 可以引用替换变量“&1”来查看传递的用户名。

    9.13 从命令行将值传递给 PL/SQL 过程

    如果您创建一个过程“myproc”:

    create or replace procedure myproc (p1 in number) as
    begin
      dbms_output.put_line('The number is '||p1);
    end;
    /
    
    • 1
    • 2
    • 3
    • 4
    • 5

    并且myscript.sql 包含:

    begin
      myproc(&1);
    end;
    /
    
    • 1
    • 2
    • 3
    • 4

    然后调用:

    sqlplus hr/my_password @myscript.sql 88
    
    • 1

    如果“myproc”的参数“p1”为“IN OUT”,则此方法不起作用。 变量引用经过预处理,实际上是一个硬编码值,不能包含 OUT 值。 为了解决这个问题,您可以将替换变量分配给绑定变量。 脚本 myscript.sql 变为:

    variable mybindvar number
    begin
      :mybindvar := &1;
      myproc(:mybindvar);
    end;
    /
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    9.14 允许脚本参数是可选的并具有默认值

    目标是创建一个接受可选参数的脚本。 如果从命令行传递参数,则应使用其值。 但是,如果没有参数,那么 SQL*Plus 应该要求一个带有自定义提示的值。

    也许最接近的解决方案是使用这样的 PROMPT/DEFINE 序列。 如果 myscript.sql 是:

    -- Name: myscript.sql
    prompt Enter a value for PAGESIZE
    set termout off
    define mypar = &1
    set termout on
    prompt Setting PAGESIZE to &mypar
    set pagesize &mypar
    select last_name from employees where rownum < 20;
    exit
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    请注意,当您传递参数时,仍会显示 PROMPT 文本,但您不输入值。 PROMPT 命令是 SQL*Plus “echo” 或 “print” 语句。 (它不读取输入)。

    “&1”的唯一出现应该是定义“mypar”的地方。 对参数的所有其他引用应使用“&mypar”或“&&mypar”。

    9.15 将值传递给 Web 的 iSQL*Plus 动态报告

    略。

    9.16 为 Web 的 iSQL*Plus 动态报告定制参数提示

    9.17 为 SQL*Plus 返回状态使用变量

    要将名为“myv”的替换变量的值用作 SQL*Plus 返回状态,请使用:

    EXIT myv
    
    • 1

    在替换变量名称之前不需要和号 (&) 前缀。

    数字绑定变量需要冒号 (😃 前缀:

    EXIT :mybv
    
    • 1

    9.18 将用户名和数据库放在提示符中

    将此添加到您的 glogin.sql 或 login.sql 中:

    set sqlprompt "_user'@'_connect_identifier:SQL> "
    
    • 1

    对于查询数据库的自定义提示,请确保明确定义任何引用的替换变量。 glogin.sql 和 login.sql 可以在没有数据库连接的情况下运行。 定义变量可防止在查询失败且未定义变量时提示用户输入值:

    set termout off
    define myv = 'Not connected'
    column myc new_value myv
    select user||'@'||global_name myc from global_name;
    set sqlprompt '&myv:SQL> '
    set termout on
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    SQLPROMPT 中的变量也不是动态替换的。 可以使用上面给出的查询脚本,但要注意提示只会对原始连接有效。

  • 相关阅读:
    c语言之strcat函数使用和实现
    Hugging News #0904: 登陆 AWS Marketplace
    Day 62 单向循环链表 双链表
    Redis高级及实战
    如何修改uni微信小程序editor组件和input组件的placeholder默认样式
    freeRTOS学习(一)
    IM即时通讯开发如何实现Android版智能心跳机制
    [Go WebSocket] 为什么我选用Go重构Python版本的WebSocket服务?
    腾讯云4核8G服务器性能如何多少钱一年?
    Redis学习3——列表数据类型的操作
  • 原文地址:https://blog.csdn.net/stevensxiao/article/details/125418450