【问题标题】:DB2 - Querying two databases in SQL PLDB2 - 在 SQL PL 中查询两个数据库
【发布时间】:2019-04-01 21:58:21
【问题描述】:

我需要比较两个不同 DB2 数据库实例的数据。我们不允许建立联邦。我找到了说明如何指定从远程数据库加载数据的参考资料,以及有关如何指定数据库连接的参考资料,包括数据库名称、用户名等。理想情况下,我可以对一个数据库执行查询,然后将其与第二个数据库可以是一对一的(使用 SQL PL 循环等),也可以是单个大型连接。我已经到了 SQL PL 脚本可以依次连接到每一个的地步(它会提示我输入两者的密码),但是当我尝试查询表时它只识别第二个。

我们尝试过的: 在开头添加两个不同的 CONNECT 语句。

声明一个游标并指定数据库名称(这似乎只在从一个数据库加载到另一个数据库时才有效,我们试图避免这种情况)。

set serveroutput on@
set sqlcompat DB2@
connect to first user myname@
connect to second user myname@

-- run command: db2 -td@ -vf test3.sql
begin

    declare loop_counter int;
    call dbms_output.enable(100000);
    set loop_counter = 0;

FIRSTLOOP: for o as ord1 cursor for 
        select field1, field2 from first.firstschema.firsttable fetch first 10 rows only with ur
    do
        set loop_counter = loop_counter + 1;
        call dbms_output.put_line('Field: '||field1||', other '||field2);
    end for;
    call dbms_output.put_line('End first program: ');
SECONDLOOP: for p as ord2 cursor for 
        select field1, field2 from second.secondschema.secondtable fetch first 10 rows only with ur
    do
        set loop_counter = loop_counter + 1;
        call dbms_output.put_line('Field: '||field1||', other '||field2);
    end for;
    call dbms_output.put_line('After second call');
end@

理想情况下,两个游标循环中的每一个都将打印 10 行。实际上,无论哪个 CONNECT 第二个完成都是有效的。例如,如果我先连接到 SECOND,然后再连接到 FIRST,则第一个循环有效,第二个循环显示“..... 是一个未定义的名称”。如果我先连接到 FIRST,然后再连接到 SECOND,第一个循环会抛出错误并且我没有得到任何输出。

【问题讨论】:

    标签: database db2 multiple-instances


    【解决方案1】:

    SQL PL 一次只能连接一个数据库 - 这就是设计。

    在您的脚本示例中,第二个连接将首先关闭任何当前连接。

    联合使您可以像访问本地表一样访问远程表。

    如果您无法使用 federation ,您的选项包括:

    • 在本地实现远程表并复制数据 (这可以通过从远程光标加载来完成)。 然后,您可以使用 SQL 来比较行,因为这两个表都在同一个数据库中。 这只有在您有足够的容量来容纳同一数据库中的两个表时才可行,尽管压缩在这里会有所帮助。

    • 不使用 SQL,而是使用其他工具 例如:根据数据量和数据类型,您可以导出源/目标表 到平面文件并比较文件(差异等)。您还可以导出到管道并在内存比较中使用。 或者您可以使用 python 或 perl 或任何脚本语言并在内存中进行块比较(在所有情况下 每个线程一次只能连接到一个数据库)。

    • 使用第三方工具进行数据比较。

    • 如果您使用嵌入式 SQL,则 type-2 连接提供了另一种可能性。

    【讨论】:

    • 这就是我害怕的。我们的 DBA 熟悉复制到本地表,这是第一个建议;我们希望通过让我们动态处理不同的数据子集,这种替代方案能够更顺利地工作。我们将采用最初的方法(和/或请求某人允许我们联合)。
    【解决方案2】:

    在 Db2 for IBM i 上,联合只能通过 Db2 LUW 盒使用...

    但是,以下内容适用于 IBM i 的 Db2...

    create or replace function myschema.myudtf () 
    returns table (SERVER VARCHAR(18)
                  , as_of timestamp
                  , ORDINAL_POSITION INTEGER 
                  , JOB_NAME VARCHAR(28) 
                  , SUBSYSTEM VARCHAR(10) 
                  , AUTHORIZATION_NAME VARCHAR(10) 
                  , JOB_TYPE VARCHAR(3)
                  )
    modifies SQL data
    external action
    not deterministic
    language SQL
    specific CHKAWSJOBS
    
    begin
      declare insertStmt varchar(1500);
    
      declare global temporary table 
         GLOBAL_TEMP_MY_JOBS (
                    SERVER VARCHAR(18)
                  , as_of timestamp
                  , ORDINAL_POSITION INTEGER 
                  , JOB_NAME VARCHAR(28) 
                  , SUBSYSTEM VARCHAR(10) 
                  , AUTHORIZATION_NAME VARCHAR(10) 
                  , JOB_TYPE VARCHAR(3)
                  ) with replace;
    
      for systemLoop as systemsCursor cursor for
        select * from table( values ('mysys1'),('mysys2'),('mysys3')) 
                         as systems (server_Name)
         do                                  
           set insertStmt = 
               ' insert into GLOBAL_TEMP_MY_JOBS
                 select 
                 current_server as server, current_timestamp as as_of
                 , ordinal_position, job_name, subsystem, authorization_name, job_type
                  from table(QSYS2.ACTIVE_JOB_INFO(
                   SUBSYSTEM_LIST_FILTER => ''MYSBS'')) X
                 where exists (select 1 from ' concat server_name concat '.sysibm.sysdummy1)';
           execute immediate InsertStmt;
         end for;      
    
      return select * from GLOBAL_TEMP_MY_JOBS;
    end;
    

    上面的例子比你的用例更复杂,我从远程系统上的 UDTF 中提取数据,技巧是在 where 子句中使用 3 部分名称,强制数据库在远程机器上运行整个select 语句;将insert 放入本地计算机上的表中。

    您应该能够构建一个动态插入,只是

    set insertStmt = 'insert into lcltable
                      select field1, field2
                      from ' concat server_name concat table_name
                      concat ' fetch first 10 rows only with ur';
    

    不确定这是否适用于 Db2 LUW,但很有可能。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2022-01-07
      相关资源
      最近更新 更多