带有Select子句的RPGLE Dynamic SQL不起作用

时间:2018-05-30 10:52:15

标签: sql ibm-midrange rpgle

在阅读了几篇关于SQLRPGLE的文章并检索数据并将它们存储在数据结构数组中之后,我想出了动态的sql语句。

只要我在where where条件下使用这些动态替换字段,这样就可以正常工作。但是,正如我使用这些?选择部分中的参数,或者通常作为数据库字段的替换,结果为空。

这是DDS定义和程序:

  

TESTPF

       FLD01  FLD02   
000001    1   Text 01 
000002    2   Text 02 
000003    3   Text 03 
000004    4   Text 04 
000005    5   Text 05 
000006    6   Text 06 
000007    7   Text 07 
000008    8   Text 08 
000009    9   Text 09 
000010   10   Text 10 

我已经用一些虚拟数据填充了这个文件。这里面是什么:

  

runqry()qtemp / testpf

 D**********************************************************************************************
 D*  Standalone Fields
 D*---------------------------------------------------------------------------------------------
 D stm             s            500a   inz(*blanks)
 D fieldName01     s             10a   inz(*blanks)
 D fieldName02     s             10a   inz(*blanks)
 D fieldName03     s              2a   inz(*blanks)
 D text            s             20a   inz(*blanks)
 D
 C**********************************************************************************************
 C*  M A I N   P R O G R A M M
 C**********************************************************************************************

   stm = 'SELECT fld02 FROM testpf WHERE fld01 = 1';
   exec sql prepare s1 from :stm;
   exec sql declare c1 cursor for s1;
   exec sql open c1;
   exec sql fetch c1 into :text;
   exec sql close c1;
   dsply text;   // Prints 'Text 01'
   text = *blanks;

   stm = 'SELECT fld02 FROM testpf WHERE fld01 = ?';
   exec sql prepare s2 from :stm;
   exec sql declare c2 cursor for s2;
   fieldName03 = '2';
   exec sql open c2 using :fieldName03;
   exec sql fetch c2 into :text;
   exec sql close c2;
   dsply text;   // Prints 'Text 02'
   text = *blanks;

   stm = 'SELECT ? FROM testpf WHERE fld01 = 3';
   exec sql prepare s3 from :stm;
   exec sql declare c3 cursor for s3;
   fieldName01 = 'FLD02';
   exec sql open c3 using :fieldName01;
   exec sql fetch c3 into :text;
   exec sql close c3;
   dsply text;   // Prints ' '
   text = *blanks;

   stm = 'SELECT ? FROM testpf WHERE ? = ?';
   exec sql prepare s4 from :stm;
   exec sql declare c4 cursor for s4;
   fieldName01 = 'FLD02';
   fieldName02 = 'FLD01';
   fieldName03 = '4';
   exec sql open c4 using :fieldName01, :fieldName02, :fieldName03;
   exec sql fetch c4 into :text;
   exec sql close c4;
   dsply text;   // Prints ' '
   text = *blanks;

   *inlr = *on;
 C********************************************************************************************** 

这是该计划:

  

TST001I

DSPLY  Text 01
DSPLY  Text 02
DSPLY         
DSPLY         
DSPLY         

这是输出:

Сompletion with Tab

有人可以帮我解释为什么会这样吗?

1 个答案:

答案 0 :(得分:3)

使用预准备语句时,只要在静态语句中使用主变量,就可以使用?作为参数标记。在你的四个样本预备语句中,前三个应该有效,但第三个不会返回你所期望的,因为它相当于:

SELECT 'FLD02' FROM testpf WHERE fld01 = 3

我希望收到值'FLD02'作为结果,而不是FLD02列中的值。这是因为?不是字符串替换标记,而是参数字段标记。您无法使用它来选择列,但您可以使用它来提供比较值或输出常量。

第四个示例是有效的SQL,但它等同于:

SELECT 'FLD02' FROM testpf WHERE 'FLD01' = '4'

由于'FLD01'不等于'4',因此不返回任何内容。

这样做的另一个结果是?可用于为预准备语句提供数值。所以你可以这样做:

dcl-s seqno   Packed(5:0);

exec sql declare c2 cursor for s2;

stm = 'SELECT fld02 FROM testpf WHERE fld01 = ?';
exec sql prepare s2 from :stm;
seqno = 2;
exec sql open c2 using :seqno;

另请注意,我将游标的声明删除到逻辑流之外的某处,因为声明不是可执行语句。我看到声明在子程序中的程序,该子程序在包含光标打开的单独子程序之前调用。这在语义上是不正确的。 DECLARE CURSOR语句更准确地等同于RPGLE dcl-语句。但是因为SQL预编译器线性处理源,很大程度上不考虑子例程或子过程,所以要求DECLARE CURSOR在物理上位于源OPEN之前。

一般来说,我喜欢在SET OPTION语句之后立即将我的SQL声明放在程序的头部,该语句必须是程序中嵌入的第一个SQL。这是我在使用预准备语句时放置声明的地方。我也声明了声明名称,尽管这不是必须的。尽管如此,还是有一点问题,当使用静态SQL和本地范围的主机变量时就存在这种问题。为了解决这个问题,我在使用子程序时声明静态游标有点不同。 SQL预编译器识别出子过程使用本地范围的变量,因此如果要声明具有本地范围的主变量的静态游标,则主机变量和游标声明必须在同一范围内。这意味着我必须在与open相同的子过程中声明我的静态游标。我仍然将光标声明在RPGLE dcl-语句附近,以便将声明保持在一起。