DB2/400打开游标的替代方案

DB2/400打开游标的替代方案,db2,ibm-midrange,db2-400,Db2,Ibm Midrange,Db2 400,我正在运行DB2fori,v7r2tr3 我被告知打开光标会带来很多开销,应该尽可能避免。据我所知,使用var2将EXECUTE转换为var1是一种替代方法,但我无法让它工作。我得到一份工作 这是我的存储过程: BEGIN DECLARE STMT1 VARCHAR ( 500 ) ; SET STMT1 = 'SELECT SUBSTR (''' || TRIM(ITEM) || ''' , ( LENGTH ( TRIM ( PREFIX ) ) + 1 ) , ( 2

我正在运行DB2fori,v7r2tr3

我被告知打开光标会带来很多开销,应该尽可能避免。据我所知,使用var2将EXECUTE转换为var1是一种替代方法,但我无法让它工作。我得到一份工作

这是我的存储过程:

BEGIN 
DECLARE STMT1 VARCHAR ( 500 ) ;     

SET STMT1 =     'SELECT SUBSTR (''' || TRIM(ITEM) || ''' , ( LENGTH ( TRIM ( PREFIX ) ) + 1 ) , ( 20 - LENGTH ( TRIM ( PREFIX ) ) ) ) ' ||
                'FROM   MYLIB.MYTABLE ' ||
                'WHERE  PREFIX = SUBSTR(''' || TRIM(ITEM) || ''', 0,LENGTH ( TRIM ( PREFIX ) ) + 1 ) ' ||
                'AND    SEQ1 = ' || TYPE || ' ' ||
                'ORDER BY   LENGTH ( TRIM ( PREFIX) ) DESC , TRIM (PREFIX) DESC ' ||
                'FETCH FIRST 1 ROWS ONLY ';

PREPARE S1 FROM STMT1; 
EXECUTE S1 INTO BASEITEM;

--OPEN C1 ; 
--  FETCH C1 INTO BASEITEM ; 
--CLOSE C1 ; 

IF(TRIM(BASEITEM) = '') THEN
    SET BASEITEM = ITEM;
END IF;
END  ; 
它有三个定义如下的变量:

IN ITEM CHAR(20) CCSID 37 DEFAULT  ''  , 
IN TYPE INT DEFAULT  1  , 
INOUT BASEITEM CHAR(20) DEFAULT  '' 
当我执行到。。。这将不会编译,如果我使用。。。它将被编译,但BASEITEM最终为空,IF语句解析为true

我试着按照文档中的说明进行操作,显然INTO只能用于CALL或VALUES INTO语句。因此,我尝试按照文档进行操作,但不知道如何使用查询

注*:我希望最终将串联变量更改为使用参数标记,但接下来我会担心这个问题

我想我应该发布正在使用的表: MYLIB.MYTABLE

我本质上是传入一个字符串,然后从字符串中删除最长的前缀。然后我返回了新字符串。SEQ1只是前缀1或2的类型,SEQ2是前缀的长度

EXECUTE只能用于DML语句,不能用于查询,因此除了声明动态游标之外,实在没有其他选择。话虽如此,打开游标并没有任何开销,就像以任何其他方式执行查询一样,因为对于任何查询,游标仍将被创建并隐式打开(如果不是显式的话)

游标的效率低于基于集合的操作,例如,当从表2中选择某个内容而不是执行类似“插入到表1”的操作时,其中。。。在表2上打开一个光标,并在循环中将行逐个插入表1。在这种情况下,效率低下的原因是执行单行插入或更新而不是多行更新,而不是光标本身,这与打开光标会带来大量开销的说法完全不同

因为在您的情况下,无论如何只获取一条记录,所以这个循环vs.set参数不适用。

EXECUTE只能用于DML语句,不能用于查询,因此除了声明动态游标之外,实在没有其他选择。话虽如此,打开游标并没有任何开销,就像以任何其他方式执行查询一样,因为对于任何查询,游标仍将被创建并隐式打开(如果不是显式的话)

游标的效率低于基于集合的操作,例如,当从表2中选择某个内容而不是执行类似“插入到表1”的操作时,其中。。。在表2上打开一个光标,并在循环中将行逐个插入表1。在这种情况下,效率低下的原因是执行单行插入或更新而不是多行更新,而不是光标本身,这与打开光标会带来大量开销的说法完全不同


因为在您的情况下,您无论如何只获取一条记录,所以此循环vs.set参数不适用。

您将收到一个错误,因为EXECUTE stmt INTO的工作方式与您认为的不一样

真正的问题是,您正试图在不需要的时候使用动态SQL。改用static

BEGIN 

  SELECT SUBSTR (TRIM(ITEM), ( LENGTH ( TRIM ( PREFIX ) ) + 1 ) , ( 20 - LENGTH ( TRIM ( PREFIX ) ) ) )
    INTO BASEITEM
    FROM   MYLIB.MYTABLE 
   WHERE  PREFIX = SUBSTR(TRIM(ITEM), 0,LENGTH ( TRIM ( PREFIX ) ) + 1 )
          AND    SEQ1 = TYPE
   ORDER BY   LENGTH ( TRIM ( PREFIX) ) DESC , TRIM (PREFIX) DESC
   FETCH FIRST 1 ROWS ONLY;

IF(TRIM(BASEITEM) = '') THEN
    SET BASEITEM = ITEM;
END IF;
END  ;

您将收到一个错误,因为EXECUTE stmt INTO的工作方式与您认为的不同

真正的问题是,您正试图在不需要的时候使用动态SQL。改用static

BEGIN 

  SELECT SUBSTR (TRIM(ITEM), ( LENGTH ( TRIM ( PREFIX ) ) + 1 ) , ( 20 - LENGTH ( TRIM ( PREFIX ) ) ) )
    INTO BASEITEM
    FROM   MYLIB.MYTABLE 
   WHERE  PREFIX = SUBSTR(TRIM(ITEM), 0,LENGTH ( TRIM ( PREFIX ) ) + 1 )
          AND    SEQ1 = TYPE
   ORDER BY   LENGTH ( TRIM ( PREFIX) ) DESC , TRIM (PREFIX) DESC
   FETCH FIRST 1 ROWS ONLY;

IF(TRIM(BASEITEM) = '') THEN
    SET BASEITEM = ITEM;
END IF;
END  ;

好的,谢谢你的澄清。基本上可以归结为N+1问题,使用某些方法执行较少的查询来实现给定的目标。说得好。但让我指出,动态SQL与静态SQL相比,有额外的开销。除了没有参数标记的动态语句外,@d.lanza38还容易受到SQL注入攻击。在这种情况下,甚至不需要动态SQL。@Charles问题是关于一般游标的开销,而不是静态和动态语句。好的,谢谢你澄清这一点。基本上可以归结为N+1问题,使用某些方法执行较少的查询来实现给定的目标。说得好。但让我指出,动态SQL与静态SQL相比,有额外的开销。除了没有参数标记的动态语句外,@d.lanza38还容易受到SQL注入攻击。在这种情况下,甚至不需要动态SQL。@Charles这个问题是关于一般游标的开销,与之相比,我不知道,不是关于静态和动态语句。我希望我可以标记多个答案,因为这将是其中之一,因为它非常有用,@Mustacio刚刚回答了实际问题。如您所建议的,不使用动态sql大大提高了这一过程的速度。我最初开始使用动态SQL,因为我试图使用LIKE子句将字符串与前缀进行比较,并且必须使用%符号连接。当我放弃时,我从未意识到
将其转换回将提高性能。@d.lanza38,作为将来的参考,您应该能够在静态语句中使用LIKE。您必须使用dynamic的唯一地方是当表名更改时。动态可能会简化复杂的WHERE或ORDER BY…但如果在WHERE或ORDER BY中选择动态SQL而不是CASE语句,请确保使用参数标记“WHERE mycl=?”而不是将用户输入直接连接到语句中。我希望我可以标记多个答案,因为这将是其中之一,因为它非常有用,@穆斯塔西奥刚刚回答了实际问题。如您所建议的,不使用动态sql大大提高了这一过程的速度。我最初开始使用动态SQL,因为我试图使用LIKE子句将字符串与前缀进行比较,并且必须使用%符号连接。当我放弃这一点时,我从未意识到将其转换回会提高性能。@d.lanza38,作为将来的参考,您应该能够在静态语句中使用LIKE。您必须使用dynamic的唯一地方是当表名更改时。动态可能会简化复杂的WHERE或ORDER BY…但如果在WHERE或ORDER BY中选择动态SQL而不是CASE语句,请确保使用参数标记“WHERE mycl=?”而不是将用户输入直接连接到语句中。