【问题标题】:How to pass a parameter from shell script to SQL script?如何将参数从 shell 脚本传递到 SQL 脚本?
【发布时间】:2022-09-27 10:59:59
【问题描述】:

我有 2 个脚本 - 一个 shell 和一个 sql。

我的 shell 脚本与此类似:

export nbr=&1 

runsql script_name.sql

我试图在运行脚本时为 nbr 传递参数。

对应的sql脚本如下:

insert into table1

select * from table2 

where year=\'&1\'

我得到如下错误:

\"enter value for year: old 22: where year=\'$1\') 
                       new 22: where year=\'commit\')\"
  • $nbr 无处使用...
  • 我将 nbr 作为占位符来传递在 sql 脚本中使用的参数 \"year\'。这是导致错误的原因吗?
  • 您还没有显示 commit 被传递,那么它来自 runsql 是什么 - 另一个脚本或此脚本中的函数?还是在调用 shell 脚本时在命令行上?输出是(部分 - 提示来自哪里?)您使用set verify on 看到的内容,但您显示的是$1 而不是&1。所以这似乎不是你真正在运行的。如果您显示您的实际代码,而不是显着不同的东西,那将真的很有帮助。
  • Runsql 是另一个脚本中的一个函数,它具有运行所需的所有必要的 orasql 连接等。日志文件显示其中 &1 被替换为 \"commit\" 的输出,这实际上来自 runsql 脚本。我更正了$。对于那个很抱歉!我基本上只是想将数据从一个表复制到另一个表,但它有数亿条记录,所以我试图按年插入它们。

标签: sql bash oracle shell scripting


【解决方案1】:

我将通过一个基于我自己的脚本的示例来展示如何轻松处理它。 在这个脚本中,我定义了一个简单的函数run_sql(DESCR, SCRIPT, DATABASES),其中

  • DESCR - 简短描述
  • SCRIPT - sqlplus 运行参数,即脚本名称及其参数
  • DATABASES - 上面定义的要运行它的 dbname 列表

然后我们可以像这样轻松地使用它:

run_sql "1st script" "@sql1.sql param1" db1 db2
run_sql "2nd script" "@sql2.sql param1 param2 param3" db1 db2 db3

在这里我们执行:

  • “sql1.sql”在 db1 和 db2 上有 1 个参数
  • “sql2.sql”在 db1、db2 和 db3 上有 3 个参数

我们将所有输出保存到自己的日志文件中。

带有测试输出的完整示例:https://gist.github.com/xtender/465951befeed7f0ae1a3fe112dcd7fe4

简单脚本test.sh

#!/bin/bash

# Here you can define your db connection strings:
db1=xtender/pass@PDB19C_11
db2=xtender/pass@PDB19C_11
db3=xtender/pass@PDB19C_11
#####################################################################
# functions:
# Function syntax: run_sql(DESCR, SCRIPT, DATABASES)
# where
#   DESCR - short description
#   SCRIPT - sqlplus run arguments, ie script name and its parameters
#   DATABASES - list of dbname defined above on which you want to run it
run_sql(){
  local DESCR="$1"; shift
  local SCRIPT="$1"; shift
  local databases=("$@")
  echo =================================================
  echo =   $DESCR
  echo = Going to execute $SCRIPT...
  read -a res -p "Enter 'skip' to skip this step or press Enter to execute: "
  if [[ $res = "skip" ]]
  then
    echo Skipping $SCRIPT...
  else
    echo Executing $SCRIPT...
    for db in "${databases[@]}"
        do
          local cur=${!db}
          echo Executing $SCRIPT on $db - $cur...
          sqlplus -L -S ${cur} $SCRIPT >>log-$db.log 2>&1
          echo Done.
        done
    echo =================================================
  fi
}
#####################################################################


# Here we execute a script "sql1.sql" with one argument "param1" on db1 and db2:
run_sql "1st script" "@sql1.sql param1" db1 db2

# Here we execute a script "sql2.sql" with 3 arguments on db1,db2 and db3:
run_sql "2nd script" "@sql2.sql param1 param2 param3" db1 db2 db3
echo ============================================
echo === Done
echo ============================================

然后我们可以创建sql脚本,例如sql1.sqlsql2.sqlsql1.sql需要一个参数,sql2.sql - 3个参数:

sql1.sql:

select '&1' as output from dual;
exit;

sql2.sql:

select '&1' as output from dual;
exit;

【讨论】: