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

RPGLE Dynamic SQL with Select clause does not work

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

只要我将这些动态替换字段用于我的 where 条件,它就可以正常工作。但只要我使用这些? select 部分中的参数,或者通常作为数据库字段的替换,结果为空。

这里是 DDS 定义和程序:

TESTPF

A**************************************************************************
A*
A*-------------------------------------------------------------------------
A*
A          R TESTPFR
A
A            FLD01          2S 0
A            FLD02         20A
A
A**************************************************************************

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

runqry () qtemp/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 

这是程序:

TST001I

 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********************************************************************************************** 

这是输出:

DSPLY  Text 01
DSPLY  Text 02
DSPLY         
DSPLY         
DSPLY         

谁能帮我解释一下为什么会这样?

使用准备好的语句时,只要可以在静态语句中使用主变量,就可以使用 ? 作为参数标记。在您的四个准备好的示例语句中,前三个应该可以工作,尽管第三个不会 return 您似乎期望的,因为它等同于:

SELECT 'FLD02' FROM testpf WHERE fld01 = 3

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

第四个样本有效SQL,但它等价于:

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

这将 return 什么都没有,因为 '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 在一个子例程中,该子例程在包含游标打开的单独子例程之前调用。这在语义上是不正确的。 DECLARE CURSOR 语句更正确地等效于 RPGLE dcl- 语句。但是因为 SQL 预编译器线性处理源代码,在很大程度上不考虑子例程或子过程,所以要求 DECLARE CURSOR 在物理上位于源代码中的 OPEN 之前。

通常我喜欢把我的 SQL 声明放在程序的开头,紧跟在 SET OPTION 语句之后,它必须是程序中嵌入的第一个 SQL。这是我在使用准备好的语句时放置声明的地方。我也声明了语句名称,尽管这不是绝对必要的。不过,这有一个小问题,当使用 static SQL 和局部范围的主机变量时就存在这个问题。为了解决这个问题,我在使用子过程时声明静态游标有点不同。 SQL 预编译器识别子过程使用局部作用域的变量,因此如果您使用局部作用域的主变量声明静态游标,则主变量和游标声明必须在同一作用域中。这意味着我必须在与打开相同的子过程中声明我的静态游标。我仍然在 RPGLE dcl- 语句附近声明光标,以使声明保持在一起。