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

vic*_*ooi 5 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
Run Code Online (Sandbox Code Playgroud)

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;
Run Code Online (Sandbox Code Playgroud)

唯一的问题是,当我运行它时,它似乎误解了连接字符串中的冒号 (:) 与绑定变量有关:

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
Run Code Online (Sandbox Code Playgroud)

我已经用大括号 ({}) 转义了上面的内容,但它似乎仍然抱怨绑定变量。

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

干杯,维克多

Ale*_*ole 4

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

destination_connstring VARCHAR(20) := '&6';
Run Code Online (Sandbox Code Playgroud)

我不认为 PL/SQL 变量赋值支持转义,如果支持的话,LIKE您必须在调用脚本之前修改输入,这并不理想。


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

您还需要使用某种形式的动态 SQL 根据传递的参数和游标值采取操作;并且COPY是一个 SQL*Plus 命令,因此无论如何您都无法从 PL/SQL 调用它。spool我建议您使用 PL/SQL 块通过和生成一个单独的 SQL 脚本,其中包含所有命令dbms_output,然后在块完成后执行该脚本。就像是:

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;
Run Code Online (Sandbox Code Playgroud)

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

您甚至不需要为此使用 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;
Run Code Online (Sandbox Code Playgroud)