如何将bash变量传递给sqlplus,然后将该输出传递给另一个变量

时间:2015-09-24 19:46:35

标签: sql linux oracle bash

因此,我要做的是清除Oracle数据库中PDB的审核日志。 PDB的名称每次都可以不同,所以我不能将tnsnames直接用于sqlplus进入PDB来执行此操作。我将命令传递给bash,然后将它们传递给SQLPLUS命令。除了一个之外,这些工作中的每个都工作,我似乎无法弄清楚如何让它工作。

我的代码是

AUDIT="DELETE FROM SYS.AUD$ WHERE NTIMESTAMP# < sysdate-30;"
FINDPDB="select pdb_name from dba_pdbs where pdb_name != 'PDB\$SEED';"
ALTER="alter session set container=$FINDPDB;"


sqlplus -S /nolog <<EOF1
  connect / as sysdba
  set echo off feedback off head off pages 0
  set serveroutput on
  $FINDPDB
  $ALTER
  $AUDIT
  exit;
EOF1

我一直得到的错误是

alter session set container=select pdb_name from dba_pdbs where pdb_name != 'PDB$SEED';
                              *
ERROR at line 1:
ORA-65015: missing or invalid container name

这告诉我它没有将select语句的输出传递给$ FINDPDB,而是实际的select语句本身。

有没有办法可以将此值传递给ALTER变量并让它改变会话并清除sys.aud $表?

2 个答案:

答案 0 :(得分:0)

我手头没有Oracle实例,但我认为有两种方法可以做到这一点:

  1. 通过SQL * Plus建立多个连接
    1. 首先,检索pdb_name
    2. 其次,设置容器并删除审核。
  2. 使用单个SQL * Plus但使用两个named pipes
    1. 一个用于发送生成的SQL命令
    2. 二读SQL * Plus输出
  3. 作为替代方式,我应该使用“真正的”编程语言(Ruby,Python,JavaScript),它们更专用于处理从数据库读取的数据。

    编辑:经过一些搜索,可以在PL / SQL中完成

    DECLARE
       v_pdb_name VARCHAR2(255);
    BEGIN
       SELECT pdb_name INTO v_pdb_name FROM dba_pdbs WHERE pdb_name != 'PDB\$SEED';
       EXECUTE IMMEDIATE 'ALTER SESSION SET container='||v_pdb_name;
       DELETE FROM sys.aud$ WHERE ntimestamp# < sysdate-30;
    END;
    /
    

答案 1 :(得分:0)

  

我一直得到的错误是

alter session set container=select pdb_name from dba_pdbs where pdb_name != 'PDB$SEED';
                            *
ERROR at line 1:
ORA-65015: missing or invalid container name
     

这告诉我它没有将select语句的输出传递给$ FINDPDB,而是实际的select语句本身。

我不明白为什么你希望这会将SELECT查询的输出传递给$FINDPDB。你将一个很长的字符串放在一起,bash传递给sqlplus的标准输入,然后写入stdout来自sqlplus的输出。在任何时候,bash都不会选择sqlplus输出的某些行并将它们放入shell变量中。

实际上,在调用sqlplus之前,请尝试将echo $ALTER添加到bash脚本中。你很可能会发现输出是

alter session set container=select pdb_name from dba_pdbs where pdb_name != 'PDB$SEED';

如果是这样,那么在你开始sqlplus之前,bash已经完成了你不想要的替换。

你似乎希望bash和sqlplus有一些来回的对话。我会放弃这种方法。我没有尝试将PDB名称放入shell变量,而是将其放入sqlplus替换变量中。我会尝试类似以下内容(未经测试):

sqlplus -S /nolog <<"EOF1"
  connect / as sysdba
  set echo off feedback off head off pages 0
  set serveroutput on
  column pdb_name new_value pdb
  select pdb_name from dba_pdbs where pdb_name != 'PDB\$SEED';
  alter session set container = &pdb.;
  delete from sys.aud$ where ntimestamp# < sysdate - 30;
  exit;
EOF1

我们使用column pdb_name new_value pdb将替换变量pdb设置为从名为pdb_name的列中选择的下一个值。然后,我们运行select查询以获取PDB名称,并将其存储在pdb中。一旦我们在替换变量中获得了这个值,我们就可以发出alter session语句来更改PDB,最后发出delete语句来删除PDB中的数据。

我很想避免使用PL / SQL块,正如另一个答案中所建议的那样。我希望在PDB更改后解析delete语句,因为我希望确保来自&#39;更正的数据&#39; PDB正在删除。我对使用PL / SQL的关注是PL / SQL编译器将确定在解析块时要删除哪个表,这将在它运行块之前,因此在它执行alter session语句之前改变PDB。但是,我不太了解Oracle 12c中的PDB和CDB,足以说明这是真正的问题还是毫无根据的废话。

我无法访问可插拔的Oracle 12c数据库以运行此类操作,因此我无法告诉您此脚本是否有效。如果没有,希望它应该让你知道去哪里。