将变量从 bash 脚本传递到 Oracle SQL*Plus

Passing variables from bash script into Oracle SQL*Plus

我尝试了几种不同的方法(从这里和其他地方)但没有成功,希望你们中更有经验的人能够提供帮助。

这是我的shell脚本

read -p 'What is the ID? ' asnid
    if [ -z "$asnid" ]
        then 
            echo "ID is Empty"
            exit
        else 
            echo "ID, continuing to Date"
    fi
read -p 'What is the Arrival Date? (Answer in DD-MM-YY format please!) ' date

        if [[ $date =~ ^[0-9]{2}-[0-9]{2}-[0-9]{2}$ ]]
            
            then echo "Date $date is in valid format (DD-MM-YY)"

                cd /go/to/path
                sqlplus data/base@srvc @./sql.sql $asnid $date

            else echo "Date $date is in an invalid format (not DD-MM-YY)"
            exit

        fi

然后是我的 .sql 声明

    define asnid = &asnid 
    define date = &date

    update table
    set date = '&date'
        where asnid = '&asnid';
            COMMIT;
            exit;

但是,这会再次询问我变量.. 例如;

Enter value for asnid:

我知道这很简单,但是什么!!

Oracle 11g,Bash 是 RHEL 6

您正在传递位置参数,因此将它们称为 &1&2。如果您想在查询正文中使用更友好的名称,则只需更改这些名称的定义:

define asnid = &1
define date = "to_date('&2', 'DD-MM-RR')"

我已经包括 (a) 将第二个参数括在引号中,因为它需要被视为一个字符串,以及 (b) 将该字符串转换为实际日期。因为它有一个逗号,所以整个表达式也必须用双引号引起来。因此,您不需要 SQL 语句中的引号:

update table
set date = &date
where asnid = &asnid;

然后整个 to_date(...) 表达式将被替换到您的查询中,并嵌入传入的值;如果你 set verify on,你会看到这种情况发生,但你可能想要关闭它,除了测试。启用它后,脚本显示:

What is the ID? 42
ID, continuing to Date
What is the Arrival Date? (Answer in DD-MM-YY format please!) 01-09-21 Date 01-09-21 is in valid format (DD-MM-YY)

SQL*Plus: Release 12.1.0.2.0 Production on Wed Aug 25 18:12:50 2021

Copyright (c) 1982, 2014, Oracle.  All rights reserved.

Last Successful login time: Wed Aug 25 2021 18:11:54 +01:00

Connected to:
Oracle Database 12c Enterprise Edition Release 12.1.0.2.0 - 64bit Production With the Partitioning, Real Application Clusters, Automatic Storage Management, OLAP, Advanced Analytics, Real Application Testing and Unified Auditing options


old   2: set some_date = &date
new   2: set some_date = to_date('01-09-21', 'DD-MM-RR')
old   3: where asnid = &asnid
new   3: where asnid = 42

1 row updated.


Commit complete.


Disconnected from Oracle Database 12c Enterprise Edition Release 12.1.0.2.0 - 64bit Production With the Partitioning, Real Application Clusters, Automatic Storage Management, OLAP, Advanced Analytics, Real Application Testing and Unified Auditing options

(您可能还想将 -s-l 标志添加到您的 sqlplus 调用中,以抑制横幅并在凭据错误时立即退出。 )

或者您可以保持 define 简单,并在语句中应用 to_date()

define asnid = &1
define date = &2

update some_table
set some_date = to_date('&date', 'DD-MM-RR') where asnid = &asnid;

然后输出显示为:

old   2: set some_date = to_date('&date', 'DD-MM-RR')
new   2: set some_date = to_date('01-09-21', 'DD-MM-RR')
old   3: where asnid = &asnid
new   3: where asnid = 42

但如果您这样做,您不妨跳过 define,直接在声明中引用 &1&2

在这两种情况下,我都假设 &1 是一个数字。如果那实际上是一个字符串,那么也可以在语句或定义中将其括在引号中。

如果您有这个选项,您可能应该提示输入 4 位数年份的日期;可能是 ISO 格式 - 并且在 to_date().

中有匹配的格式

您也可以通过 SQL*Plus 通过 accept:

提示输入值来跳过(或最小化)shell 脚本
accept asnid number format 99999999 prompt "What is the ID? "
accept date date format 'DD-MM-RR' prompt "What is the Arrival Date? (Answer in DD-MM-YY format please!) "

update some_table
set some_date = to_date('&date', 'DD-MM-RR')
where asnid = &asnid;

然后不带参数调用它:

sqlplus data/base@srvc @/go/to/path/sql.sql

您会看到类似这样的内容,其中我使用了一些非值和无效值来演示:

SQL*Plus: Release 12.1.0.2.0 Production on Wed Aug 25 18:24:28 2021

Copyright (c) 1982, 2014, Oracle.  All rights reserved.

Last Successful login time: Wed Aug 25 2021 18:24:02 +01:00

Connected to:
Oracle Database 12c Enterprise Edition Release 12.1.0.2.0 - 64bit Production With the Partitioning, Real Application Clusters, Automatic Storage Management, OLAP, Advanced Analytics, Real Application Testing and Unified Auditing options

What is the ID?
SP2-0598: "" does not match input format "99999999"
What is the ID? 42
What is the Arrival Date? (Answer in DD-MM-YY format please!)
SP2-0685: The date "" is invalid or format mismatched "DD-MM-RR"
What is the Arrival Date? (Answer in DD-MM-YY format please!) 31-09-21
SP2-0685: The date "31-09-21" is invalid or format mismatched "DD-MM-RR"
What is the Arrival Date? (Answer in DD-MM-YY format please!) 30-09-21

old   2: set some_date = to_date('&date', 'DD-MM-RR')
new   2: set some_date = to_date('30-09-21', 'DD-MM-RR')
old   3: where asnid = &asnid
new   3: where asnid =         42

1 row updated.


Commit complete.


Disconnected from Oracle Database 12c Enterprise Edition Release 12.1.0.2.0 - 64bit Production With the Partitioning, Real Application Clusters, Automatic Storage Management, OLAP, Advanced Analytics, Real Application Testing and Unified Auditing options

这将允许 Oracle 愿意使用该格式掩码转换的日期字符串,因此它允许您输入“01-Sep-21”。如果你不想要那个,那么制作格式掩码 'FXDD-MM-RR'。 (但是,再次考虑使用 4 位数的年份和明确的格式...)