DB2 - Запрос двух баз данных в SQL PL - PullRequest
0 голосов
/ 29 марта 2019

Мне нужно сравнить данные двух разных экземпляров базы данных 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, первый цикл работает, а второй говорит: «..... это неопределенное имя». Если я выполняю соединение с ПЕРВЫМ, а затем с ВТОРОМ, первый цикл выдает ошибку, и я не получаю вывод.

Ответы [ 2 ]

1 голос
/ 29 марта 2019

SQL PL может одновременно подключаться только к одной базе данных - это проект.

В вашем примере сценария второе соединение сначала закроет любое текущее соединение.

Федерация позволяет получать доступ к удаленным таблицам, как если бы они были локальными.

Если вам запрещено использовать федерацию, вы можете выбрать следующие варианты:

  • материализация удаленной таблицы локально и копирование данных (это можно сделать через загрузку с удаленного курсора). Затем вы можете использовать SQL для сравнения строк, так как обе таблицы находятся в одной базе данных. Это возможно только в том случае, если вы располагаете достаточной емкостью для размещения обеих таблиц в одной базе данных, хотя сжатие здесь поможет.

  • не использует SQL, а использует другой инструмент Например: в зависимости от объемов данных и типов данных вы можете экспортировать исходные / целевые таблицы выровнять файлы и сравнить файлы (разные и т. д.) Вы также можете экспортировать в конвейер и использовать для сравнения памяти. Или вы можете использовать Python или Perl или любой другой язык сценариев и выполнять сравнение в памяти кусками (во всех случаях каждый поток может подключаться только к одной базе данных одновременно).

  • использовать сторонние инструменты для сравнения данных.

  • если вы используете встроенный SQL, подключение типа 2 предлагает другую возможность.

0 голосов
/ 01 апреля 2019

В Db2 для IBM i федерация доступна только через поле Db2 LUW ...

Однако в Db2 для IBM i работает следующее ...

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 в удаленной системе, трюк - это использование имени из 3 частей в предложении where, которое заставляет БД для запуска всего оператора 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, но есть хороший шанс.

...