首先,我想为我糟糕的英语道歉,我可能会错过一些关键信息给你们。
反正。我正在开发一个带有子文件的显示文件来显示一些记录。当显示一个选择时,它就像一个魅力,但现在我想为用户开发一个搜索功能。因此,当用户输入不同的搜索条件时,选择将改变,并且光标必须以新的选择以某种方式更新。我正在撕开我的头发,我真的无法让它发挥作用。
我发现了一个来自“mcpressonine”-forum的帖子,有一个人和我一样得到了完全相同的问题,他确实以某种方式解决了这个问题,但我真的不明白他做了什么 - 除了将声明光标放在子程序中我也做了 - 没有成功。
这是他论坛帖子的链接: His post
如果有人解释他做了什么,我会非常感激。也许这家伙的解决方案不再有效,因为他的职位现在已经10岁了。 告诉我,如果信息不够,我会在整个过程中纠正。谢谢! 亲切的问候,Jesper
答案 0 :(得分:1)
要记住的是DECLARE
语句不是可执行文件。这是一个编译时声明。 PREPARE
和OPEN
是可执行的。
下面是一个使用动态SQL的完全正常运行的程序,请注意,DeclareCursor
子例程实际上从未被调用过。重要的是在执行PREPARE
语句时在gSqlStmt中的语句。
**FREE
ctl-opt main(mymain);
ctl-opt option(*srcstmt);
dcl-c QUOTE const('''');
dcl-s gSqlStmt varchar(500);
dcl-proc MyMain;
dcl-s company char(3);
dcl-s part char(25);
dcl-s desc char(30);
dcl-s msg char(50);
dcl-s selComp char(3);
selComp = 'A06';
gSqlStmt = 'select pmco#, pmpart, pmdesc'
+ ' from pdpmast'
+ ' where pmco# = ' + QUOTE + selComp + QUOTE;
exsr OpenCursor;
exsr FetchData;
exec SQL close C1;
selComp = 'A15';
gSqlStmt = 'select pmco#, pmpart, pmdesc'
+ ' from pdpmast'
+ ' where pmco# = ' + QUOTE + selComp + QUOTE;
exsr OpenCursor;
exsr FetchData;
exec SQL close C1;
*INLR = *ON;
return;
begsr DeclareCursor;
exec SQL
declare C1 cursor for S1;
endsr;
begsr OpenCursor;
exec SQL prepare S1 from :gSqlStmt;
exec SQL open C1;
endsr;
begsr FetchData;
exec sql fetch next from C1 into :company, :part, :desc;
msg = company + ':' + part + ':' + %subst(desc:1:20);
dsply msg;
endsr;
end-proc;
除了没有任何错误处理之外,上面还包含将输入变量selComp直接连接到语句中的错误做法。由于SQL注入攻击,这在任何语言中都不是一个好主意。
下面是使用参数标记的更好版本。请注意,该语句不再需要更改。所以我只需要准备一次。记录选择取决于调用OPEN ... USING...
语句时selComp的值。
**FREE
ctl-opt main(mymain);
ctl-opt option(*srcstmt);
dcl-s gSqlStmt varchar(500);
dcl-proc MyMain;
dcl-s company char(3);
dcl-s part char(25);
dcl-s desc char(30);
dcl-s msg char(50);
dcl-s selComp char(3);
gSqlStmt = 'select pmco#, pmpart, pmdesc'
+ ' from pdpmast'
+ ' where pmco# = ?';
exec SQL prepare S1 from :gSqlStmt;
selComp = 'A06';
exsr OpenCursor;
exsr FetchData;
exec SQL close C1;
selComp = 'A15';
exsr OpenCursor;
exsr FetchData;
exec SQL close C1;
*INLR = *ON;
return;
begsr DeclareCursor;
exec SQL
declare C1 cursor for S1;
endsr;
begsr OpenCursor;
exec SQL open C1 using :selComp;
endsr;
begsr FetchData;
exec sql fetch next from C1 into :company, :part, :desc;
msg = company + ':' + part + ':' + desc;
dsply msg;
endsr;
end-proc;
但是,这里实际上并不需要动态SQL。带有主变量的静态语句可以正常工作。使用静态SQL,我不需要PREPARE
任何内容,也不需要在OPEN
上指定selComp。所有这些都是在编译时自动完成的。
**FREE
ctl-opt main(mymain);
ctl-opt option(*srcstmt);
dcl-s gSqlStmt varchar(500);
dcl-proc MyMain;
dcl-s company char(3);
dcl-s part char(25);
dcl-s desc char(30);
dcl-s msg char(50);
dcl-s selComp char(3);
selComp = 'A06';
exsr OpenCursor;
exsr FetchData;
exec SQL close C1;
selComp = 'A15';
exsr OpenCursor;
exsr FetchData;
exec SQL close C1;
*INLR = *ON;
return;
begsr DeclareCursor;
exec SQL
declare C1 cursor for
select pmco#, pmpart, pmdesc
from pdpmast
where pmco# = :selComp;
endsr;
begsr OpenCursor;
exec SQL open C1;
endsr;
begsr FetchData;
exec sql fetch next from C1 into :company, :part, :desc;
msg = company + ':' + part + ':' + desc;
dsply msg;
endsr;
end-proc;
答案 1 :(得分:0)
您只能在嵌入式SQL程序或存储过程中声明一次游标。您还可以声明多个游标。但链接到该游标的SQL语句可能会随时间而变化。
推荐帖子中的建议仍然有效。您可以将游标声明一次(例如在存储过程中),但只要光标首次关闭(如果它已打开)并且只要新的SQL-,游标引用的语句就会随时间而变化。语句已成功准备,然后光标重新打开等。