带有 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-
语句附近声明光标,以使声明保持在一起。
在阅读了几篇关于 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-
语句附近声明光标,以使声明保持在一起。