我有一个小的 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/