如何在 sql / cobol 中使用参数标记
How to use parameter markers in sql / cobol
我必须编写一个 COBOL 程序,从文件中读取一些记录并用它们进行一些计算。如果使用非空白过滤器调用例程,则应过滤结果。
我尝试在 SQL 中使用参数标记。这是我的尝试:
100 IDENTIFICATION DIVISION. 19/11/07
200 PROGRAM-ID. MINIMALEX. 01/07/20
300 AUTHOR. ME. 01/07/20
400 DATE-WRITTEN. JULY 2020. 01/07/20
500 *----------------------------------------------------------------* 01/07/20
600 *--- Minimal example. ---* 01/07/20
700 *----------------------------------------------------------------* 01/07/20
800 ENVIRONMENT DIVISION. 19/11/07
900 CONFIGURATION SECTION. 19/11/07
1000 SOURCE-COMPUTER. IBM-AS400. 19/11/07
1100 OBJECT-COMPUTER. IBM-AS400. 19/11/07
1200 SPECIAL-NAMES. DECIMAL-POINT IS COMMA. 28/12/10
1300 *----------------------------------------------------------------* 01/07/20
1400 INPUT-OUTPUT SECTION. 19/11/07
1500 FILE-CONTROL. 19/11/07
1600 *----------------------------------------------------------------* 19/11/07
1700 DATA DIVISION. 19/11/07
1800 FILE SECTION. 19/11/07
1900 *----------------------------------------------------------------* 19/11/07
2000 WORKING-STORAGE SECTION. 19/11/07
2100 *--- Variables for SQL. 01/07/20
2200 EXEC SQL 01/07/20
2300 INCLUDE SQLCA 01/07/20
2400 END-EXEC. 01/07/20
2500 EXEC SQL 01/07/20
2600 INCLUDE SQLDA 01/07/20
2700 END-EXEC. 01/07/20
2800 01/07/20
2900 01 WK-NAME PIC X(80). 01/07/20
3000 01 WK-LASTNAME PIC X(80). 01/07/20
3100 01 WK-SELECT PIC X(34). 01/07/20
3200 01 WK-WHERE PIC X(65). 01/07/20
3300 01 WK-STATEMENT PIC X(100). 01/07/20
3400 *----------------------------------------------------------------* 01/07/20
3500 LINKAGE SECTION. 19/11/07
3600 01 LK-NAME PIC X(80). 01/07/20
3700 *----------------------------------------------------------------* 01/07/20
3800 PROCEDURE DIVISION USING LK-NAME. 01/07/20
3900 *----------------------------------------------------------------* 01/07/20
4000 A01-START. 01/07/20
4100 *--- Create and insert data into file. 01/07/20
4200 EXEC SQL 01/07/20
4300 DROP TABLE QTEMP/T 01/07/20
4400 END-EXEC. 01/07/20
4600 EXEC SQL 01/07/20
4700 CREATE TABLE QTEMP/T 01/07/20
4800 (NAME CHAR (80), LASTNAME CHAR (80)) 01/07/20
4900 END-EXEC. 01/07/20
5100 EXEC SQL 01/07/20
5200 INSERT INTO QTEMP/T VALUES ("ALFRED", "HITCHCOCK") 01/07/20
5300 END-EXEC. 01/07/20
5500 01/07/20
5600 MOVE 'SELECT NAME, LASTNAME FROM QTEMP/T' TO WK-SELECT. 01/07/20
5700 21/03/08
5800 MOVE SPACES TO WK-WHERE. 01/07/20
5900 MOVE 0 TO SQLN. 01/07/20
6000 01/07/20
6100 IF LK-NAME NOT = SPACES 01/07/20
6200 STRING 'WHERE NAME LIKE ("%" CONCAT ' 01/07/20
6300 'TRIM(CAST(? AS CHAR(80))) CONCAT "%")' 01/07/20
6400 DELIMITED BY SIZE INTO WK-WHERE 01/07/20
6500 ADD 1 TO SQLN 01/07/20
6600 END-IF. 01/07/20
6700 28/04/08
6800 STRING WK-SELECT DELIMITED BY SIZE 01/07/20
6900 ' ' DELIMITED BY SIZE 01/07/20
7000 WK-WHERE DELIMITED BY ' ' INTO WK-STATEMENT 01/07/20
7100 END-STRING. 21/04/08
7200 30/06/20
7300 EXEC SQL 30/06/20
7400 PREPARE STMT FROM :WK-STATEMENT 01/07/20
7500 END-EXEC. 30/06/20
7700 EXEC SQL 30/06/20
7800 DESCRIBE INPUT STMT INTO :SQLDA 01/07/20
7900 END-EXEC. 30/06/20
8100 21/04/08
8200 *--- Setting values for SQLDA. 01/07/20
8300 IF LK-NAME NOT = SPACES 01/07/20
8400 SET SQLDATA(1) TO ADDRESS OF LK-NAME 01/07/20
8500 END-IF. 01/07/20
8600 30/06/20
8700 EXEC SQL 21/04/08
8800 DECLARE SQL_LIST CURSOR FOR STMT 01/07/20
8900 END-EXEC. 21/04/08
9000 21/04/08
9100 EXEC SQL 21/04/08
9200 OPEN SQL_LIST 01/07/20
9300 END-EXEC. 21/04/08
9500 21/04/08
9600 A01-FETCH. 01/07/20
9700 EXEC SQL 01/07/20
9800 FETCH NEXT FROM SQL_LIST INTO :WK-NAME, :WK-LASTNAME 01/07/20
9900 END-EXEC. 01/07/20
10100 IF SQLCODE NOT = 0 01/07/20
10200 GO TO A01-CLOSE 01/07/20
10300 END-IF. 01/07/20
10400 01/07/20
10500 *--- Do some stuff with the fetched data, then fetch next row. 01/07/20
10600 GO TO A01-FETCH. 01/07/20
10700 21/04/08
10800 A01-CLOSE. 01/07/20
10900 EXEC SQL 13/02/20
11000 CLOSE SQL_LIST 01/07/20
11100 END-EXEC. 13/02/20
11300 13/02/20
11400 A01-END. 01/07/20
11500 GOBACK. 01/07/20
不幸的是,当我 运行 程序(给 LK-NAME 一个非空白的值)时,OPEN 语句 returns a SQLCODE -313 (The number of EXECUTE 或 OPEN 语句中指定的主机变量与准备好的 SQL 语句中出现的参数标记(问号)的数量不同。)在我看来,主机变量和参数标记的数量都是1、问题出在哪里?
编辑
根据 Charles 的建议,第 9200 行更改为
OPEN SQL_LIST USING DESCRIPTOR :SQLDA
这现在给出 SQLCODE -822。
编辑 2
经过进一步研究,我了解到每个宿主变量必须与链接部分中的指示变量相关联,并且 SQLIND 的出现必须指向这些指示变量的地址。谢谢@Charles
了解该平台会有所帮助..
但是,我希望看到您打算在 open 语句中的参数生成器中使用的变量。
EXEC SQL
OPEN SQL_LIST USING :LK-NAME
END-EXEC.
open语句是用来替换参数标记的值被替换的地方。
话虽如此,您可能需要考虑静态 SQL 而不是动态的。
静态SQL不需要准备...它只是看起来像
EXEC SQL
DECLARE SQL_LIST CURSOR FOR
SELECT NAME, LASTNAME FROM QTEMP/T
WHERE :LK-NAME = ' '
OR NAME LIKE ( '%' CONCAT TRIM(:LK-NAME) CONCAT '%')
END-EXEC.
EXEC SQL
OPEN SQL_LIST
END-EXEC.
请注意,即使在这里,LK-NAME 的值也是在打开游标时传入的,DECLARE CURSOR
确实是一个编译时语句。
编辑
您可以使用描述符区域,如果这种情况下打开会根据文档指定 OPEN…USING DESCRIPTOR descriptor-name
。老实说,我从来没有这样做过。
您已阅读 embedded SQL programming 手册,正确吗?
是的,通常静态语句更快。只要与动态版本相比不是太复杂即可。
我必须编写一个 COBOL 程序,从文件中读取一些记录并用它们进行一些计算。如果使用非空白过滤器调用例程,则应过滤结果。
我尝试在 SQL 中使用参数标记。这是我的尝试:
100 IDENTIFICATION DIVISION. 19/11/07
200 PROGRAM-ID. MINIMALEX. 01/07/20
300 AUTHOR. ME. 01/07/20
400 DATE-WRITTEN. JULY 2020. 01/07/20
500 *----------------------------------------------------------------* 01/07/20
600 *--- Minimal example. ---* 01/07/20
700 *----------------------------------------------------------------* 01/07/20
800 ENVIRONMENT DIVISION. 19/11/07
900 CONFIGURATION SECTION. 19/11/07
1000 SOURCE-COMPUTER. IBM-AS400. 19/11/07
1100 OBJECT-COMPUTER. IBM-AS400. 19/11/07
1200 SPECIAL-NAMES. DECIMAL-POINT IS COMMA. 28/12/10
1300 *----------------------------------------------------------------* 01/07/20
1400 INPUT-OUTPUT SECTION. 19/11/07
1500 FILE-CONTROL. 19/11/07
1600 *----------------------------------------------------------------* 19/11/07
1700 DATA DIVISION. 19/11/07
1800 FILE SECTION. 19/11/07
1900 *----------------------------------------------------------------* 19/11/07
2000 WORKING-STORAGE SECTION. 19/11/07
2100 *--- Variables for SQL. 01/07/20
2200 EXEC SQL 01/07/20
2300 INCLUDE SQLCA 01/07/20
2400 END-EXEC. 01/07/20
2500 EXEC SQL 01/07/20
2600 INCLUDE SQLDA 01/07/20
2700 END-EXEC. 01/07/20
2800 01/07/20
2900 01 WK-NAME PIC X(80). 01/07/20
3000 01 WK-LASTNAME PIC X(80). 01/07/20
3100 01 WK-SELECT PIC X(34). 01/07/20
3200 01 WK-WHERE PIC X(65). 01/07/20
3300 01 WK-STATEMENT PIC X(100). 01/07/20
3400 *----------------------------------------------------------------* 01/07/20
3500 LINKAGE SECTION. 19/11/07
3600 01 LK-NAME PIC X(80). 01/07/20
3700 *----------------------------------------------------------------* 01/07/20
3800 PROCEDURE DIVISION USING LK-NAME. 01/07/20
3900 *----------------------------------------------------------------* 01/07/20
4000 A01-START. 01/07/20
4100 *--- Create and insert data into file. 01/07/20
4200 EXEC SQL 01/07/20
4300 DROP TABLE QTEMP/T 01/07/20
4400 END-EXEC. 01/07/20
4600 EXEC SQL 01/07/20
4700 CREATE TABLE QTEMP/T 01/07/20
4800 (NAME CHAR (80), LASTNAME CHAR (80)) 01/07/20
4900 END-EXEC. 01/07/20
5100 EXEC SQL 01/07/20
5200 INSERT INTO QTEMP/T VALUES ("ALFRED", "HITCHCOCK") 01/07/20
5300 END-EXEC. 01/07/20
5500 01/07/20
5600 MOVE 'SELECT NAME, LASTNAME FROM QTEMP/T' TO WK-SELECT. 01/07/20
5700 21/03/08
5800 MOVE SPACES TO WK-WHERE. 01/07/20
5900 MOVE 0 TO SQLN. 01/07/20
6000 01/07/20
6100 IF LK-NAME NOT = SPACES 01/07/20
6200 STRING 'WHERE NAME LIKE ("%" CONCAT ' 01/07/20
6300 'TRIM(CAST(? AS CHAR(80))) CONCAT "%")' 01/07/20
6400 DELIMITED BY SIZE INTO WK-WHERE 01/07/20
6500 ADD 1 TO SQLN 01/07/20
6600 END-IF. 01/07/20
6700 28/04/08
6800 STRING WK-SELECT DELIMITED BY SIZE 01/07/20
6900 ' ' DELIMITED BY SIZE 01/07/20
7000 WK-WHERE DELIMITED BY ' ' INTO WK-STATEMENT 01/07/20
7100 END-STRING. 21/04/08
7200 30/06/20
7300 EXEC SQL 30/06/20
7400 PREPARE STMT FROM :WK-STATEMENT 01/07/20
7500 END-EXEC. 30/06/20
7700 EXEC SQL 30/06/20
7800 DESCRIBE INPUT STMT INTO :SQLDA 01/07/20
7900 END-EXEC. 30/06/20
8100 21/04/08
8200 *--- Setting values for SQLDA. 01/07/20
8300 IF LK-NAME NOT = SPACES 01/07/20
8400 SET SQLDATA(1) TO ADDRESS OF LK-NAME 01/07/20
8500 END-IF. 01/07/20
8600 30/06/20
8700 EXEC SQL 21/04/08
8800 DECLARE SQL_LIST CURSOR FOR STMT 01/07/20
8900 END-EXEC. 21/04/08
9000 21/04/08
9100 EXEC SQL 21/04/08
9200 OPEN SQL_LIST 01/07/20
9300 END-EXEC. 21/04/08
9500 21/04/08
9600 A01-FETCH. 01/07/20
9700 EXEC SQL 01/07/20
9800 FETCH NEXT FROM SQL_LIST INTO :WK-NAME, :WK-LASTNAME 01/07/20
9900 END-EXEC. 01/07/20
10100 IF SQLCODE NOT = 0 01/07/20
10200 GO TO A01-CLOSE 01/07/20
10300 END-IF. 01/07/20
10400 01/07/20
10500 *--- Do some stuff with the fetched data, then fetch next row. 01/07/20
10600 GO TO A01-FETCH. 01/07/20
10700 21/04/08
10800 A01-CLOSE. 01/07/20
10900 EXEC SQL 13/02/20
11000 CLOSE SQL_LIST 01/07/20
11100 END-EXEC. 13/02/20
11300 13/02/20
11400 A01-END. 01/07/20
11500 GOBACK. 01/07/20
不幸的是,当我 运行 程序(给 LK-NAME 一个非空白的值)时,OPEN 语句 returns a SQLCODE -313 (The number of EXECUTE 或 OPEN 语句中指定的主机变量与准备好的 SQL 语句中出现的参数标记(问号)的数量不同。)在我看来,主机变量和参数标记的数量都是1、问题出在哪里?
编辑
根据 Charles 的建议,第 9200 行更改为
OPEN SQL_LIST USING DESCRIPTOR :SQLDA
这现在给出 SQLCODE -822。
编辑 2
经过进一步研究,我了解到每个宿主变量必须与链接部分中的指示变量相关联,并且 SQLIND 的出现必须指向这些指示变量的地址。谢谢@Charles
了解该平台会有所帮助..
但是,我希望看到您打算在 open 语句中的参数生成器中使用的变量。
EXEC SQL
OPEN SQL_LIST USING :LK-NAME
END-EXEC.
open语句是用来替换参数标记的值被替换的地方。
话虽如此,您可能需要考虑静态 SQL 而不是动态的。
静态SQL不需要准备...它只是看起来像
EXEC SQL
DECLARE SQL_LIST CURSOR FOR
SELECT NAME, LASTNAME FROM QTEMP/T
WHERE :LK-NAME = ' '
OR NAME LIKE ( '%' CONCAT TRIM(:LK-NAME) CONCAT '%')
END-EXEC.
EXEC SQL
OPEN SQL_LIST
END-EXEC.
请注意,即使在这里,LK-NAME 的值也是在打开游标时传入的,DECLARE CURSOR
确实是一个编译时语句。
编辑
您可以使用描述符区域,如果这种情况下打开会根据文档指定 OPEN…USING DESCRIPTOR descriptor-name
。老实说,我从来没有这样做过。
您已阅读 embedded SQL programming 手册,正确吗?
是的,通常静态语句更快。只要与动态版本相比不是太复杂即可。