глобальная временная таблица в хранимой процедуре db2 - PullRequest
0 голосов
/ 29 мая 2018

Просто попал в DB2 и решил использовать глобальную временную таблицу в моем хранимом процессе для моей задачи.

Задача будет следующая: просто заполните некоторые данные для каждого дня (в течение, например, 5 дней), выбрав случайные строки из другой таблицы, я получаю свою дату как:

    select id from (
    select id, rand() rnd from source_table) 
    where rnd>0
    order by rnd
    fetch first 1000 rows only 

Я хотел где-то хранить этот список int, чтобы использовать их снова.Идея была следующая:

            create table test (id int, dt date);


    create or replace procedure proc1 ()

    begin 

    declare v_start date default '2018-05-25'; 
    declare v_end date default '2018-05-30'; 
    declare v_dml varchar(8000);

    /*                                  this part so far doesn't work
    declare global temporary table
    session.temp_tab(id int)
    not logged on commit preserve;

    insert into session.temp_tab(id)
    select id from my_table;*/

    while v_start <= v_end DO 

        set v_dml = 'insert into test (id, dt)
                with t as (
                select 1 id, '''||v_start||''' dt from sysibm.dual
                union
                select 2 id, '''||v_start||''' dt from sysibm.dual
                union
                select 3 id, '''||v_start||''' dt from sysibm.dual)
                select *
                from t 
                where id in (1,3)';                         
    /*instead of 1,3 I would like to have list of values in some temp 
    table/array..., which I'll get 
    from the other table and can just use duriing this proc     
    I don't want to use sub select, because I'll get every time some random 
    data. But also I need that list for filter in several insert/update 
    statements*/ 
        set v_start = v_start +1 day;

        execute immediate v_dml;
        commit;
    end while;
    end 

PS Я использую DB2 LUW v10.5.0.7

UPD_1: я хотел бы выполнить операции DDL и DML в одном цикле.Например, я хочу добавить разделение, а затем вставить данные в ту же таблицу.как это:

    create or replace procedure proc1 (
                                    in in_rep int)
    begin 
    declare v_dt date; 
    declare v_end_dt date;
    declare v_add_part varchar(1024);
    declare v_id int;
    declare v_next_id int;       

            select max(id), max(dt) 
            into v_id,  v_dt
            from test;                                                                  

            set v_end_dt  = v_dt + in_rep day; 

                        while v_dt < v_end_dt DO

                                   set v_dt = v_dt +1 day;
                                   set v_next_id = v_id+1;          
                                   set v_add_part = 'alter table TEST               
                                                      add PARTITION part_'||v_next_id||'
                                                      starting from '||v_next_id||' ending at '||v_next_id;     

                                   execute immediate v_add_part;                  

                                   insert into test (id, dt)
                                   select v_next_id, v_dt 
                                   from sysibm.dual;                   
                       end while;
    end

В этом случае я получу ошибку, SQLCODE = -327, SQLSTATE = 22525 Строка не может быть вставлена, потому что она находится за пределами диапазона разделения для последнего раздела.

Причина в том, что я пытаюсь изменить таблицу и вставить одновременно, а не шаг за шагом.Но не могу понять, как это сделать, шаг за шагом, кроме замены вставки с динамическим SQL, например:

    set v_add_part = 'alter table TEST               
    add PARTITION part_'||v_next_id||'
    starting from '||v_next_id||' ending at '||v_next_id;     

    set v_ins = 'insert into test (id, dt)
    select '||v_next_id||','''||v_dt||'''
    from sysibm.dual'; 

    execute immediate v_add_part;
    execute immediate v_ins;

Ответы [ 2 ]

0 голосов
/ 29 мая 2018

Вот пример использования функции RAND () для заполнения таблицы сеанса.

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

Для производственного использования необходимо добавить соответствующую обработку ошибок.

create or replace procedure proc1 ()
language sql
specific proc1
begin 
    declare v_start date default '2018-05-25'; 
    declare v_end date default '2018-05-30'; 
    declare v_dml varchar(8000);
    declare global temporary table 
        session.temp_tab(id int not null) 
        with replace not logged on commit preserve rows;
    insert into session.temp_tab(id) 
       select int(rand()*1000) as random 
       from my_table order by random fetch first 1000 rows only;
    set v_dml = 'insert into test (id, dt) 
                 select t.id ,cast(? as date)  from session.temp_tab as t ' ;
    prepare s1 from v_dml;
    while v_start <= v_end do 
        execute s1 using v_start;
        set v_start = v_start + 1 day;
    end while;
    commit;
    end 
0 голосов
/ 29 мая 2018

Если вы используете Data Studio, это будет анализировать ваш код локально и выявлять любые синтаксические ошибки.Процедура создает для меня (на Db2 11.1 в любом случае), как только я добавил работу ROWS после PRESERVE

create or replace procedure proc1 ()

begin 

declare v_start date default '2018-05-25'; 
declare v_end date default '2018-05-30'; 
declare v_dml varchar(8000);

--                                  this part so far doesn't work
declare global temporary table
session.temp_tab(id int)
not logged on commit preserve rows;

insert into session.temp_tab(id)
select id from my_table;

while v_start <= v_end DO 

    set v_dml = 'insert into test (id, dt)
            with t as (
            select 1 id, '''||v_start||''' dt from sysibm.dual
            union
            select 2 id, '''||v_start||''' dt from sysibm.dual
            union
            select 3 id, '''||v_start||''' dt from sysibm.dual)
            select *
            from t 
            where id in (1,3)';                         
/*instead of 1,3 I would like to have list of values in some temp 
table/array..., which I'll get 
from the other table and can just use duriing this proc     
I don't want to use sub select, because I'll get every time some random 
data. But also I need that list for filter in several insert/update 
statements*/ 
    set v_start = v_start +1 day;

    execute immediate v_dml;
    commit;
end while;
end

Кстати, ваш код будет лучше (IMHO) с использованием переменной и статического SQL, а не динамическипостроение оператора SQL.Также вы можете использовать VALUES с несколькими строками, не нужно выбирать из фиктивных DUAL таблиц.

Я не уверен, какова ваша задача, но я не уверен, что вы близки к лучшему решению здесь;; -)

...