Oracle PL/SQL - 如何转义冒号 ( :), 被误解为绑定(bind)变量

标签 oracle plsql

我有一个小的 PL/SQL 脚本,我用它来尝试在两个 Oracle 数据库实例之间复制数据。

我用(清理过的)调用 SQL 脚本:

sqlplus username/password@server.com:1434/SERVICENAME @copyTables.sql source_username source_password source_connstring destination_username destination_password destination_connstring

copyTables.sql 脚本:
SET SERVEROUTPUT ON;
DECLARE
  source_username VARCHAR2(20) := &1
  source_password VARCHAR2(20) := &2
  source_connstring VARCHAR2(2) := &3
  destination_username VARCHAR2(20) := &4
  destination_password VARCHAR2(20) := &5
  destination_connstring VARCHAR(20) := &6
  CURSOR user_table_cur IS
  SELECT table_name
  FROM user_tables
  ORDER BY table_name DESC;

BEGIN
  FOR user_table IN user_table_cur LOOP
    dbms_output.put_line(source_username);
    dbms_output.put_line(user_table.table_name);
    COPY FROM {source_username}/{source_password}@{source_connstring} TO {destination_username}/{destination_password}@{destination_connstring} APPEND user_table.table_name user_table.table_name USING SELECT* FROM user_table.table_name;
  END LOOP;
END;

唯一的问题是,当我运行它时,它似乎将连接字符串中的冒号 (:) 误解为与绑定(bind)变量有关:
Oracle Database 11g Enterprise Edition Release 11.2.0.1.0 - 64bit Production
With the Partitioning, OLAP, Data Mining and Real Application Testing options

old   2:   source_username VARCHAR2(20) := &1
new   2:   source_username VARCHAR2(20) := SANITISED
old   3:   source_password VARCHAR2(20) := &2
new   3:   source_password VARCHAR2(20) := SANITISED
old   4:   source_connstring VARCHAR2(2) := &3
new   4:   source_connstring VARCHAR2(2) := server.com:3630/SANITISED
old   5:   destination_username VARCHAR2(20) := &4
new   5:   destination_username VARCHAR2(20) := SANITISED
old   6:   destination_password VARCHAR2(20) := &5
new   6:   destination_password VARCHAR2(20) := SANITISED
old   7:   destination_connstring VARCHAR(20) := &6
new   7:   destination_connstring VARCHAR(20) := server.com:3630/SANITISED
SP2-0552: Bind variable "3630" not declared.
SQL> Disconnected from Oracle Database 11g Enterprise Edition Release 11.2.0.1.0 - 64bit Production

我已经用大括号({})转义了上述内容,但它似乎仍然提示绑定(bind)变量。

另外 - 作为附录 - 我在上面做的方式,这是将命令行参数传递给 PL/SQL 脚本的最佳实践吗?我愿意接受有关更好方法的建议。

干杯,
胜利者

最佳答案

分配位置变量时需要在位置变量周围加上引号,因此此时整个值被解释为字符串:

destination_connstring VARCHAR(20) := '&6';

我不相信 PL/SQL 变量赋值支持 LIKE 的转义。确实如此,如果是这样,您必须在调用脚本之前修改您的输入,这并不理想。

稍微偏离你原来的问题......

您还需要使用某种形式的动态 SQL 来根据传递的参数和游标值采取行动;和 COPY是一个 SQL*Plus 命令,所以无论如何你都不能从 PL/SQL 调用它。我建议您使用 PL/SQL block 通过 spool 生成包含所有命令的单独 SQL 脚本。和 dbms_output ,然后在 block 完成后执行。就像是:
SET SERVEROUTPUT ON SIZE 100000 FORMAT WRAPPED;
SET TRIMOUT ON
SET TRIMSPOOL ON
SET VERIFY OFF
SET LINES 1024

SPOOL tmp_copy_commands.sql
SET TERMOUT OFF
SET FEEDBACK OFF

DECLARE
    src_username VARCHAR2(20) := '&1';
    src_password VARCHAR2(20) := '&2';
    src_connstring VARCHAR2(40) := '&3';
    dest_username VARCHAR2(20) := '&4';
    dest_password VARCHAR2(20) := '&5';
    dest_connstring VARCHAR(40) := '&6';

    CURSOR user_table_cur IS
        SELECT table_name
        FROM user_tables
        ORDER BY table_name DESC;

BEGIN
    FOR user_table IN user_table_cur LOOP
        dbms_output.put_line('COPY FROM '
            || src_username ||'/'|| src_password ||'@'|| src_connstring
            || ' TO '
            || dest_username ||'/'|| dest_password ||'@'|| dest_connstring
            || ' APPEND ' || user_table.table_name
            || ' USING SELECT * FROM '
            || user_table.table_name ||';');
    END LOOP;
END;
/

SPOOL OFF
SET TERMOUT ON
SET FEEDBACK ON

@tmp_copy_commands

EXIT 0;

离你原来的问题更远了......

你甚至不需要为此使用 PL/SQL,除非你想使用动态 SQL 和 EXECUTE IMMEDIATE .这将与前面的示例相同:
SET TRIMOUT ON
SET TRIMSPOOL ON
SET VERIFY OFF
SET LINES 1024
SET PAGES 0
SET HEAD OFF

SPOOL tmp_copy_commands.sql
SET TERMOUT OFF
SET FEEDBACK OFF

SELECT 'COPY FROM &1./&2.@&3. TO &4./&5.@&6. APPEND '
    || table_name || ' USING SELECT * FROM ' || table_name || ';'
FROM user_tables
ORDER BY table_name DESC;

SPOOL OFF
SET TERMOUT ON
SET FEEDBACK ON

@tmp_copy_commands

exit 0;

关于Oracle PL/SQL - 如何转义冒号 ( :), 被误解为绑定(bind)变量,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/7342642/

相关文章:

sql - 重写查询替换 not in

Oracle不等运算符: ¬=

oracle - 如何更改 XMLTYPE 变量的字符集?

plsql - 更改表时 PL/SQL 类型不会更改

plsql - PL/SQL - 使用 utl_smtp 发送西里尔字符

sql - Oracle SQL 从多个元素中提取值

sql - 返回每组一列最大值的行

Oracle JDBC : Resuming a Database Change Notification Registration

java - 选择带有时间戳的记录

sql - 使用临时表复制一行的开销值得吗?