在 Oracle 脚本中使用数组

Posted

技术标签:

【中文标题】在 Oracle 脚本中使用数组【英文标题】:Using arrays in Oracle scripts 【发布时间】:2016-03-31 15:24:23 【问题描述】:

我想创建一个脚本文件来将值插入/更新到表中。为了维护,我想创建一个数组(可能是多维的)并循环通过它来插入记录。以下是表格列:

表名:REF_PROPERTY

REF_PROPERTY_ID Number PK
PACKAGE_ID Number FK
PROPERTY_NAME VarChar
PROPERTY_VALUE VarChar
OVERRIDE_VALUE Number

表名:包

PACKAGE_ID Number PK
PACKAGE_NAME VarChar
PACKAGE_VERSION VarChar

我们有几个包(10-15 个),每个包都有自己的一组属性(40 - 50 个属性);有些是一样的。我想为所有这些包创建一个脚本文件,而不是为每个包创建单独的脚本文件。

我想做的是这样的(写这个有点非 PL/SQL 格式,更多的是一种编码方式): 声明一个数组变量:

V_MYARR VARRAY;
myArr[1] = ['v2|v3|v4', 'property1', 'propertyValue1', 1];
myArr[2] = ['v1|v2|v3|v4', 'property2', 'propertyValue2', 0];
myArr[3] = ['v2|v3|v4|v5', 'property3', 'propertyValue3', 1];

通过上述操作,我可以在脚本中维护属性及其值。当我们为任何包版本添加新属性时,我们将其放在这里并运行脚本。

假设我想为包版本 v2 运行脚本。为包名和版本声明变量并获取包ID:

V_PKG_NAME VarChar := 'Package1'
V_PKG_VERSION VarChar := 'v2';
V_PKG_ID Number;
SELECT PACKAGE_ID INTO V_PKG_ID WHERE PACKAGE_NAME = V_PKG_NAME AND PACKAGE_VERSION = V_PKG_VERSION;

现在,我想遍历数组,用管道分隔符 (|) 分割第一个元素,检查那里是否存在版本 v2,如果存在,则插入/更新表中的值。

for int arrRow in myArr
   --split the first element of myArr[arrRow][0] by | and store in a new array variable splitArr
   --loop through splitArr
   --if V_PKG_VERSION == splitArr[I] then insert.
v2 exists in myArr[arrRow][0] so the insert would be (check if value exists before insert):
INSERT INTO REF_PROPERTY VALUES (REF_PROP_SEQ.nextval, V_PKG_ID, myArr[arrRow][1], myArr[arrRow][2], myArr[arrRow][3]);

end loop;

同样,当我想运行包版本 v3 的脚本时,我将包版本设置为 v3,然后运行脚本。

V_PKG_VERSION VarChar := 'v3';

我希望这可以很好地说明我想要做什么,以及这是否是最小化脚本文件数量的好方法。最后,如果这样的事情在 Oracle PL/SQL 中是可行的。

提前致谢!

【问题讨论】:

这对我来说听起来有点矫枉过正。在某处,您必须指定要插入的值;为什么不把它作为插入语句的一部分呢?例如。类似insert into ref_property (....) select 'some val1a', 'some val2a', ... from dual union all select 'some val1b', 'some val2b', ... from dual union all ... 谢谢。您能否提供一个详细的 SQL 示例?我将不胜感激。我意识到我想要做的是矫枉过正。我真的想在一个文件中维护/指定所有包的属性名称和它们的值,所以在未来,我们不会弄乱这些值,我们确切地知道它们被设置为什么。目前,我为每个包版本大约有 12 个脚本文件,维护已成为一场噩梦,尤其是当其他人要添加自己的脚本时。 【参考方案1】:

如果我是你,我会设置一个插入或合并语句来处理插入/更新。

类似:

merge into packages tgt
using (select 'Package1' package_name, 'v1' package_version from dual union all
       select 'Package1' package_name, 'v2' package_version from dual union all
       select 'Package1' package_name, 'v3' package_version from dual union all
       select 'Package1' package_name, 'v4' package_version from dual union all
       select 'Package2' package_name, 'v1' package_version from dual union all
       select 'Package2' package_name, 'v2' package_version from dual) src
  on (tgt.package_name = src.package_name and tgt.package_version = src.package_version)
when not matched then
  insert (tgt.package_id, tgt.package_name, tgt.package_version)
  values (packages_seq.nextval, src.package_name, src.package_version);

merge into ref_property tgt
using (select pkg.package_id,
              property_name,
              property_value,
              override_value
       from   packages pkg
              inner join (select 'Package1' package_name, 'v1' package_version, 'property2' property_name, 'propertyValue2' property_value, 0 override_value from dual union all
                          select 'Package1' package_name, 'v2' package_version, 'property1' property_name, 'propertyValue1' property_value, 1 override_value from dual union all
                          select 'Package1' package_name, 'v2' package_version, 'property2' property_name, 'propertyValue2' property_value, 0 override_value from dual union all
                          select 'Package1' package_name, 'v2' package_version, 'property3' property_name, 'propertyValue3' property_value, 1 override_value from dual union all
                          select 'Package1' package_name, 'v3' package_version, 'property1' property_name, 'propertyValue1' property_value, 1 override_value from dual union all
                          select 'Package1' package_name, 'v3' package_version, 'property2' property_name, 'propertyValue2' property_value, 0 override_value from dual union all
                          select 'Package1' package_name, 'v3' package_version, 'property3' property_name, 'propertyValue3' property_value, 1 override_value from dual union all
                          select 'Package1' package_name, 'v4' package_version, 'property1' property_name, 'propertyValue1' property_value, 1 override_value from dual union all
                          select 'Package1' package_name, 'v4' package_version, 'property2' property_name, 'propertyValue2' property_value, 0 override_value from dual union all
                          select 'Package1' package_name, 'v4' package_version, 'property3' property_name, 'propertyValue3' property_value, 1 override_value from dual union all
                          select 'Package1' package_name, 'v5' package_version, 'property3' property_name, 'propertyValue3' property_value, 1 override_value from dual union all
                          select 'Package1' package_name, 'v1' package_version, 'property1' property_name, 'propertyValue2' property_value, 0 override_value from dual union all
                          select 'Package1' package_name, 'v1' package_version, 'property4' property_name, 'propertyValue4' property_value, 1 override_value from dual union all
                          select 'Package1' package_name, 'v2' package_version, 'property4' property_name, 'propertyValue5' property_value, 0 override_value from dual) prop
                on (pkg.package_name = prop.package_name and pkg.package_version = prop.package_version))
  on (tgt.package_id = src.package_id and tgt.property_name = src.property_name)
when not matched then
  insert (tgt.package_id, tgt.property_name, tgt.property_value, tgt.override_value)
  values (src.package_id, src.property_name, src.property_value, src.override_value)
--optional:
when matched then
  update set tgt.property_value = src.property_value,
             tgt.override_value = src.override_value;

这样做的好处是您可以为每个属性设置不同的值,以防软件包版本之间发生变化。

通过使用MERGE,您的脚本可以重新运行而不会搞砸。我在第二条语句的更新子句中添加了以防您希望能够更新先前设置的值。

【讨论】:

非常感谢您。我现在试一试。感谢帮助! :)

以上是关于在 Oracle 脚本中使用数组的主要内容,如果未能解决你的问题,请参考以下文章

在 oracle 中导出脚本中的更改(使用 Toad ?)

关于如何在 Oracle 数据库中使用 VBA 执行 SQL 脚本的建议

使用 SqlPlus 执行 Oracle 脚本;如果有任何异常,在脚本处理之前进入状态

Oracle每天自动备份脚本

Oracle pl/sql 从物理目录中读取文件的内容

如何在 bash 脚本中连接到 Oracle 数据库?