Loop 中的 DB2 更新不执行

DB2 update in Loop does not execute

我有以下代码:

  BEGIN
DECLARE cmd VARCHAR(1024); DECLARE attr CHAR(10); 
DECLARE attr2 CHAR(10); 
DECLARE at_end INTEGER DEFAULT 0;
DECLARE not_found CONDITION FOR SQLSTATE '02000';
DECLARE updstr1 VARCHAR(1024);
DECLARE updstr2 VARCHAR(1024);


DECLARE c1 CURSOR FOR SELECT cmd, attr, attr2 
                      FROM commandtbl2;

DECLARE CONTINUE HANDLER FOR not_found SET at_end = 1;

SET updstr1 = 'update commandtbl3 t2 set t2.XXXX = attr where t2.cmd=cmd';
SET updstr2 = 'update commandtbl3 t2 set t2.XXXX= attr2 where t2.cmd=cmd';
OPEN c1;

ins_loop: LOOP

  FETCH c1 INTO cmd, attr, attr2; 

  IF at_end = 1 THEN
    LEAVE ins_loop;
  ELSEIF cmd != '' THEN
    ITERATE ins_loop;
  END  IF;

  set updstr1= REPLACE(updstr1,'XXXX','attr');
  set updstr2= REPLACE(updstr2,'XXXX','attr2');

  EXECUTE IMMEDIATE updstr1;
  EXECUTE IMMEDIATE updstr2;


END LOOP;

CLOSE c1;
END@

它全部运行没有错误,但是当我检查 commandtbl3 时,没有任何更新。所有值均为 NULL,但应被替换。两个表中有 7 行,其中 5 行具有匹配的 cmd 值,因此应该更新这 5 行。

我不确定是替换不起作用还是立即执行。

通过调试我发现,updstr1 和 2 变量在替换后是空的...但是为什么?

你能帮帮我吗? 谢谢, 流浪汉

此处要求的是 commandtbl3 和 2 的定义:

CREATE TABLE "TEST"."COMMANDTBL3" (
    "ID" INTEGER NOT NULL GENERATED ALWAYS AS IDENTITY ( START WITH 1 INCREMENT BY 1 MINVALUE 1 MAXVALUE 2147483647 NO CYCLE CACHE 2 NO ORDER ), 
    "CMD" VARCHAR(1024 OCTETS) NOT NULL, 
    "ATTR" CHAR(10 OCTETS), 
    "ATTR2" CHAR(10 OCTETS), 
    CONSTRAINT "CC1455789123996" PRIMARY KEY
    ("ID")
)

CREATE TABLE "TEST"."COMMANDTBL2" (
    "ID" INTEGER NOT NULL GENERATED ALWAYS AS IDENTITY ( START WITH 1 INCREMENT BY 1 MINVALUE 1 MAXVALUE 2147483647 NO CYCLE CACHE 2 NO ORDER ), 
    "CMD" VARCHAR(1024 OCTETS) NOT NULL, 
    "ATTR" CHAR(10 OCTETS), 
    "ATTR2" CHAR(10 OCTETS), 
    CONSTRAINT "CC1455789123996" PRIMARY KEY
    ("ID")
)

COmmandtbl3 的 CMD 等于 commandtbl2 除了 2 行(总共 7 行)并且 attr 和 attr2 在 commandtbl3 中是 NMULL。我希望通过更新将 commandtbl2 attr 和 attr2 的值写入 commandtbl3 并替换命令,这样我就可以使用占位符 XXXX

这是工作代码:

如果有人遇到同样的问题,这里是工作代码,即使从一开始就改变了(现在 while 循环等):

BEGIN
DECLARE EOF INTEGER DEFAULT 0;
DECLARE cmd VARCHAR(1024); DECLARE attr CHAR(10); 
DECLARE attr2 CHAR(10); 
DECLARE not_found CONDITION FOR SQLSTATE '02000';
DECLARE updstr1 VARCHAR(1024);
DECLARE updstr2 VARCHAR(1024);
DECLARE stmt1 STATEMENT;
DECLARE stmt2 STATEMENT;

DECLARE c1 CURSOR FOR SELECT cmd, attr, attr2 
                  FROM commandtbl2 order by cmd;

DECLARE CONTINUE HANDLER FOR NOT FOUND SET EOF = 1;

SET updstr1 = 'update commandtbl3 t2 set t2.XXXX = ? where t2.cmd= ?';
SET updstr2 = 'update commandtbl3 t2 set t2.XXXX= ? where t2.cmd= ?';
set updstr1= REPLACE(updstr1,'XXXX','attr');
set updstr2= REPLACE(updstr2,'XXXX','attr2');
insert into temptbl(text1,text2) values(updstr1,updstr2);

prepare stmt1 from updstr1;
prepare stmt2 from updstr2;

OPEN c1;


WHILE EOF = 0 DO

FETCH from c1 INTO cmd, attr, attr2; 
EXECUTE stmt1 using attr, cmd;
EXECUTE stmt2 using attr2, cmd;

END WHILE;

CLOSE c1;
END@

您的代码中存在一些逻辑错误。

  1. 在你的循环中:

    IF at_end = 1 THEN
      LEAVE ins_loop;
    ELSEIF cmd != '' THEN
      ITERATE ins_loop;
    END  IF;
    

    ELSEIF 语句告诉 DB2,如果 cmd(来自 commandtbl2)是任何东西 是一个空字符串,它应该跳过本次循环迭代中的剩余步骤(即什么都不做,只跳回到循环开始时的 FETCH 语句)。

    这可能就是您没有看到任何事情发生的原因。

  2. 正如@mustaccio 在上面的评论中提到的,看起来您假设 DB2 会在您执行 EXECUTE IMMEDIATE 语句时神奇地用它们的值替换变量。您的声明:

    update commandtbl3 t2 set t2.XXXX = attr where t2.cmd=cmd
    

    您的代码将替换 XXXX,但确实 看起来 就像您假设 = attr=cmd 也将替换为在 FETCH 语句中设置的值。事实并非如此。

    看这个例子:

    DECLARE GLOBAL TEMPORARY TABLE t1 (c1 int) 
    ON COMMIT PRESERVE ROWS WITH REPLACE
    @
    
    BEGIN
        DECLARE v1 INT;
        DECLARE vSQL VARCHAR(128);
    
        SET vSQL = 'INSERT INTO SESSION.T1 values (v1)';
        SET v1 = 12;
    
        EXECUTE IMMEDIATE vSQL;
    END
    @
    

    当数据库到达EXECUTE IMMEDIATE语句时,它不会在运行时将v1替换为v1的值。它将执行确切的语句 INSERT INTO SESSION.T1 values (v1)。这当然会失败,因为 v1 对数据库没有任何意义。

    在您的情况下,EXECUTE IMMEDIATE 语句不会 失败 因为 attrcmd 确实对数据库有意义 – 它们是 table commandtbl3 中的列名。因此,您执行的更新语句将是(在 REPLACE 语句之后):

    update commandtbl3 t2 set t2.attr = attr where t2.cmd=cmd
    update commandtbl3 t2 set t2.attr2 = attr2 where t2.cmd=cmd
    

    这些基本上是 no-ops - 就像 UPDATE T1 SET C1 = C1 WHERE C2 = C2.

    这是一个很好的例子,说明了为什么不应使用与数据库中的列相同的名称来声明变量。它增加了混乱并可以隐藏逻辑错误。