【问题标题】:global temporary table in db2 stored proceduredb2 存储过程中的全局临时表
【发布时间】:2018-05-29 10:55:27
【问题描述】:

刚刚进入 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 

附:我使用 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;

【问题讨论】:

  • 您的代码示例中有多个语法错误和拼写错误。除此之外,还不清楚您通过重复 insert 想要达到什么目的。建议您修正错误和拼写错误并改进您的问题
  • 您使用的是 Oracle 还是 DB2?
  • @mao 抱歉,我已经更改了代码。现在它起作用了。并试图更清楚地了解我的任务。谢谢
  • @jarlh 我使用 DB2

标签: sql db2 procedure


【解决方案1】:

这是使用 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 

【讨论】:

  • 谢谢@mao 抱歉回复晚了,我找到了一些解决方法,只有时间再玩一次。但是还是想学这个话题。是的,我确实像你用 rand 写的那样。以上是唯一的例子。我不生成数据,但也使用我的表格。只是想给出最大的有效例子。我也有错误处理。您的全局临时表解决方案运行良好!我也知道动态 sql,但在这里我遇到了下一个问题。 >
  • 最好创建一个新问题,因为症状 -327 与您的原始问题无关。不要在更新或 cmets 中提出新问题。一问一症。
【解决方案2】:

如果您使用 Data Studio,它将在本地解析您的代码并突出显示任何语法错误。一旦我在PRESERVE 之后添加了工作ROWS,该过程就会为我创建(无论如何都是在Db2 11.1 上)

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

顺便说一句,您的代码会更好(恕我直言)使用变量和静态 SQL,而不是动态构建 SQL 语句。您也可以将VALUES 与多行一起使用,无需从虚拟DUAL 表中进行选择。

我不确定您的任务是什么,但我不确定您是否已接近最佳解决方案... ;-)

【讨论】:

  • 谢谢@P。弗农是的,这样做。在预先评论中回答。我完全同意我离最好的解决方案还很远——但我会做到的:)
猜你喜欢
  • 2015-12-11
  • 1970-01-01
  • 2023-04-08
  • 1970-01-01
  • 2021-09-02
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多