如何在 Shell 脚本中运行多个 SQL 脚本文件

Posted

技术标签:

【中文标题】如何在 Shell 脚本中运行多个 SQL 脚本文件【英文标题】:How to run multiple SQL script files in a Shell script 【发布时间】:2019-02-12 11:12:40 【问题描述】:

我必须创建 1 个 UNIX Shell 脚本。在那个 shell 脚本中,我想从同一个目录运行多个 SQL 脚本文件。我是这样用的-

#!usr/bin/ksh
SQLPATH = /usr/sql/
(cd $SQLPATH;
'sqlplus usr/password@sid <<EOF
 spool <db_file>.log
 @<db_name>.sql
 set echo off
 set heading off
 spool off
 &&

 spool <db_file2>.log
 @<db_name2>.sql
 set echo off
 set heading off
 spool off
 &&

 spool <db_file3>.log
 @<db_name3>.sql
 set echo off
 set heading off
 spool off
 exit;
 EOF')

exit 0

有多个这样的 SQL 脚本,我必须为每个 SQL 脚本创建日志文件,所以我在这里使用了spool。每个 SQL 脚本文件执行后 我用&amp;&amp;。所以当我定义 PATH 时,在这里和第三行 ; 中使用 &amp;&amp; 是否很好。请提供更好的解决方案。

【问题讨论】:

单引号是怎么回事? (同样,变量赋值中的= 周围不允许有空格,并且不允许缩进结束heredoc 的EOF)。我看不出您的代码将如何按照当前编写的方式工作。 @CharlesDuffy 实际上有大约 20 个 SQL 脚本文件,它们是 3-4 个不同位置的路径,因此在 shell 脚本中经常使用路径我在这里声明变量。这就是我在这里使用cd 的原因。同样在EOF 之后,答案中提到的&amp;&amp; 的用途是什么。 foo &amp;&amp; barif foo; then bar; fi 的简写,即仅当 foo 成功完成时运行 bar。我想这就是你想问的问题——你希望&amp;&amp; 在你自己的代码中是什么意思? 【参考方案1】:

不要覆盖系统PATH(或现在的SQLPATH),也不要将命令放在单引号中。对私有变量使用小写字母,并且在赋值中等号周围不能有空格;但是你只使用一次的变量无论如何都没用,所以我把它拿出来,硬编码cd参数。

我猜你想要类似的东西

#!/usr/bin/ksh

# No spaces around equals sign, and don't use uppercase for private variables
# But why use a variable at all anyway
#sqlpath=/usr/sql
cd /usr/sql  # is this really necessary and useful??

sqlplus usr/password@sid <<____EOF &&
 spool <db_file>.log
 @<db_name>.sql
 set echo off
 set heading off
 spool off
____EOF

sqlplus usr/password@sid <<____EOF &&
 spool <db_file2>.log
 @<db_name2>.sql
 set echo off
 set heading off
 spool off
____EOF

sqlplus usr/password@sid <<____EOF
 spool <db_file3>.log
 @<db_name3>.sql
 set echo off
 set heading off
 spool off
____EOF

# exit 0  # Not necessary or useful

如果可以在单个会话中执行多个sqlplus 命令,那将是一个明显的改进;但我猜sqlplus 无法表达你对&amp;&amp; 的意思(这个语法似乎有quite distinct meaning in sqlplus)。

【讨论】:

我可以直接使用cd /usr/sql而不使用()吗?EOF之前的____是什么意思。要运行每个 SQL 脚本文件,我必须每次通过sqlplus 连接 DB,或者只连接一次,然后运行所有 SQL 脚本。你能帮我解决这个问题吗? 括号创建了一个子shell,但整个脚本已经在它自己的shell实例中运行,所以子shell没有任何用处。你可能根本不需要cd(你有这个目录的写权限吗?)。下划线只是为了便于阅读——&lt;&lt; 之后的标记可以是任何文本。我不明白你的最后一句话,但它似乎与这个答案的最后一段相吻合。 当我运行上面的 shell 脚本然后它显示一个错误。 -ksh: &lt;file_name&gt;.ksh: not found [No such file or directory] @ShahinP 问题不在于脚本,而在于您运行它的方式。我无法告诉你出了什么问题,因为你已经用&lt;file_name&gt; 替换了真实的东西,但也许你正在寻找./&lt;file_name&gt;.ksh 我已经从 2 种类型 ./&lt;file_name&gt;.kshksh &lt;file_name&gt;.ksh 运行,但两次都显示相同的错误【参考方案2】:

制作函数

#!/usr/bin/ksh
SQLPATH=/usr/sql # Offtopic: Better use lowercase for your own variables

process_sql_and_log() 
   if [ $# -ne 2 ]; then
      echo "Usage: $0 sqlfile logfile"
      return 1
   fi
   sqlplus usr/password@sid <<EOF
spool $2
@$1
set echo off
set heading off
spool off
exit;
EOF


  cd "$SQLPATH" &&
  process_sql_and_log db_name.sql  db_file.log  &&
  process_sql_and_log db_name2.sql db_file2.log &&
  process_sql_and_log db_name3.sql db_file3.log

exit 0

【讨论】:

以上是关于如何在 Shell 脚本中运行多个 SQL 脚本文件的主要内容,如果未能解决你的问题,请参考以下文章

如何在 shell 脚本中运行 SQL 查询时获得类似 SQLPLUS 的输出

LINUX下shell脚本如何执行 sql脚本 到DB2数据库?

如何从一个脚本运行多个 Python/Shell 脚本

Shell 脚本中的 SQL* PLUS 连接问题

Docker:如何知道 mongo 是不是在 Alpine/node 中使用 shell 脚本文件运行

使用 Shell 脚本运行 SQL 查询并返回 CSV 格式的输出