Прочитав несколько статей о SQLRPGLE и извлечении данных и сохранении их в массивах структур данных, я придумал динамические операторы sql.
Это отлично работает, пока я использую эти динамические поля для замены для своего условия where. Но как я их использую? параметр в части выбора или вообще в качестве замены полей базы данных результат будет пустым.
Вот определение 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
Может кто-нибудь помочь мне и объяснить, почему это так?


При использовании подготовленного оператора вы можете использовать ? в качестве маркера параметра везде, где вы можете использовать переменную хоста в статическом операторе. Из ваших четырех подготовленных примеров операторов первые 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 в источнике.
Обычно я предпочитаю помещать свои SQL-объявления во главе программы сразу после оператора SET OPTION, который должен быть первым SQL, встроенным в программу. Здесь я помещаю объявления, когда использую подготовленные операторы. Я также объявляю имя оператора, хотя в этом нет строгой необходимости. Однако для этого есть небольшая ошибка, которая существует при использовании статического SQL с переменными хоста с локальной областью действия. Чтобы справиться с этим, я немного по-другому объявляю статические курсоры при использовании подпроцедур. Прекомпилятор SQL распознает, что подпроцедуры используют переменные с локальной областью действия, поэтому, если вы объявляете статический курсор с переменными узла с локальной областью действия, переменные узла и объявление курсора должны находиться в одной области. Это означает, что я должен объявить свои статические курсоры в той же подпроцедуре, что и open. Я по-прежнему объявляю курсор рядом с операторами RPGLE dcl-, чтобы объявления были вместе.
Не уверен, что вы имеете в виду, покажите пример кода, и, возможно, кто-нибудь сможет вам это объяснить.