【实习之 T100 开发】Genero FGL (TIPTOP4GL) 学习笔记,2021 金九银十
[【实习】T100 学习笔记](
)
[](
)CURSOR
=========================================================================
在 Genero FGL 语言中,当下达 DATABASE dstabase_id
指令后,即与数据库执行链接,也就是可以开始进行数据的 查询(SELECT)、更改(UPDATE)、新增(INSERT)等 动作。
在处理数据时若只有 单笔数据 的选取,则可用 单纯的 SQL 指令即可。
若是要抓取 多笔数据 处理时,就会因抓取的特性不同(例如:一次只抓一笔数据处理,完成后再抓次笔,如『个人资料表』;或一次全部抓取,一起编辑,如『个人门禁进出记录表』等),而需使用不同的 指标(CURSOR)。
[](
)CONSTRUCT:获取用户输入组成【WHERE 条件】
作用:让用户在画面上输入查询条件(通称 Query By Example;QBE),以取得用户的查询范围数据。
用户的查询数据会组成一串 【WHERE 条件】,并置入设定好的变量中。若使用者未输入任何条件,即按下『确定』离开 CONSTRUCT
,系统也会自动于此变量中补入 1=1
。
当 域名 column_list 与 变量名 field_list 相同时,可以采用语法 2
char_variable 为接取用户输入数据的 字符串变量(建议以 STRING 格式变量接取)
column_list 为对应到表格(TABLE)的域名清单(逗号隔开)
field_list 为画面(WINDOW 或是 FORM)上的字段代码清单(逗号隔开)
若有增加 控制区段 (如
ON ACTION
等),则就要加上END CONSTRUCT
语法 1 示例:
CONSTRUCT BY NAME l_str ON employee, salary
ON IDLE 10
EXIT PROGRAM
END CONSTRUCT
经过上图用户输入的条件,在程序中进行了拼接,形成一个【WHERE 条件】:
l_str = "employee='1000" AND salary>30000"
后续在组 SQL 指令时,即可通过此变量组出符合条件的 SQL 查询指令。
[](
)PREPARE:将【SQL 字符串】转成【可执行 SQL】
若已经得到一个完整的【WHERE 条件】后,接下来即可将此条件,组合成 SQL 字符串,再转换为一个完整且可以抓取符合条件的 SQL 指令。
执行完 CONSTRUCT
后,系统只能得到一个 SQL 字符串,并非为『可执行的指令』,因此必须通过 PREPARE
指令,将此 SQL 字符串转换成『可执行的 SQL 指令』。
PREPARE
会将字符串传入数据库查核语法的正确性,再回传一个 prepared-id
后续调用。
statement-name 是一个
PREPARE
完成后的 可执行 SQL(prepared-id)执行
PREPARE
指令前必须先拼接好 SELECT 语句。
LET l_sql = "SELECT * FROM employee_file",
"WHERE", l_str # l_str 是经过 CONSTRUCT 得到的【WHERE 条件】
PREPARE emp_pre FROM l_sql
[](
)FREE:释放 PREPARE 的记录
FREE 用于 释放 PREPARE 的记录。
语法:FREE statement-name
LET l_str = " employee='1000' AND salary>'30000' "
LET l_sql = " SELECT * FROM employee_file WHERE ", l_str
PREPARE emp_pre FROM l_sql
...
FREE emp_pre
[](
)数据的查询
Genero FGL 中有两种查询用的指标(CURSOR)可以运用在资料的查询
SCROLLING CURSOR
Non-SCROLLING CURSOR
SCROLLING CURSOR 通常运用在 单文件控制 或 查询类 的程序,如『个人资料表』般的作业,可以随机抓取数据,一次一笔,再处理完后可以选择 往前一比、往后一笔 或 往这个查询序列中的任何一笔数据 移动的指针(CURSOR)。
DECLARE cursor_id SCROLL CURSOR [WITH HOLD] FOR sql statement
OPEN cursor_id [USING value]
FETCH [first|last|previous|next| cursor_id INTO variable
CLOSE cursor_id
Non-SCROLLING CURSOR 通常运用在 双文件控制程序 或 报表 程序,如『个人出缺勤统计表』般的作业,抓取数据是 依序 (seguential) 的方式,一次可以将合条件要求的资料一笔接着一笔的抓出,直到资料全数抓完(或被强制终止)为止。
DECLARE cursor_id CURSOR [WITH HOLD] FOR sql statement
FOREACH cursor_id
[USING value]
[INTO variable ]
...
END FOREACH
[](
)SCROLLING CURSOR(DECLARE、OPEN、FETCH、CLOSE)
说明:通常用于 查询程序,可以 随即抓取资料。
通过 DECLARE 定义
利用 OPEN 开启该 CURSOR
例:OPEN test01_cursor
通过
FETCH cursor_name INTO 变量
抓取资料
DECLARE 概述
语法 1:使用 已知的 SQL 语句 进行 CURSOR 声明
DECLARE cursor_name SCROLL CURSOR [WITH HOLD]
FOR sql_statement
语法 2:使用 已声明的 PREPARED ID 来进行 CURSOR 声明
DECLARE cursor_name SCROLL CURSOR [WITH HOLD]
FOR prepared_id
语法 3:使用 已知的 STRING 语句 进行 CURSOR 声明
DECLARE cursor_name SCROLL CURSOR [WITH HOLD]
FROM string-expression
OPEN 概述
语法:
OPEN cursor_name [USING 变量名称]
本指令可用 STATUS 来检查是否执行成功
使用 cursor 之前要先 OPEN CURSOR,开启游标
此语句仅决定符合的数据,并不是真正从数据库中抓取数据
示例:
LET g_sql = "SELECT * FROM cta_file WHERE ROWID = ?"
DECLARE cta_cl CURSOR FROM g_sql
:
OPEN cta_cl USING l_ata01
FETCH 概述
语法:
FETCH cursor_id INTO program_variable
当声明为 SCROLLING CURSOR 时,可以配合以下移动 Cursor 的指令:
不同 FETCH 指令下 CURSOR 动作示意图:
![在这里插入图片描述](https://img-blog.csdnimg.cn/20210121175228809.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubm
V0L3dlaXhpbl80MzczNDA5NQ==,size_16,color_FFFFFF,t_70)
LET l_sql = "SELECT * FROM employee_file", "WHERE", l_str
PREPARE emp_pre FROM l_sql
DECLARE emp_cus SCROLL CURSOR
[WITH HOLD] FOR emp_pre
OPEN emp_cus # OPEN CURSOR
FETCH FIRST emp_cus INTO l_emp.* #抓第一笔
CLOSE 概述
语法:
CLOSE cursor_id
说明:关闭并释放指标(CURSOR)的储存空间
综合示例
DATABASE ds #声明数据库
MAIN
DEFINE a STRING
DEFINE b,c CHAR(10)
使用 SQL 语句 声明 CURSOR
DECLARE test01 SCROLL CURSOR FOR
SELECT zz01 FROM zz_file WHERE zz01 = "axmt410"
OPEN test01
FETCH FIRST test01 INTO b #将 cursor 指向符合条件的第一笔
DISPLAY b
LET c = "axmt410"
LET a = "SELECT zz01 FROM zz_file WHERE zz01='",c CLIPPED,"' "
使用 STRING 语句 声明 CURSOR
DECLARE test02 SCROLL CURSOR FROM a
OPEN test02
FETCH LAST test02 INTO b #将 cursor 指向符合条件的最后一笔
DISPLAY b
END MAIN
[](
)Non-SCROLLING CURSOR(DECLARE、FOREACH)
说明:常运用在 报表程式,抓取资料的方式是 依序 (seguential) 的方式。
通过 DECLARE 定义
利用 FOREACH 指令抓资料
DECLARE 概述
语法 1:使用 已知的 SQL 语句 进行 CURSOR 声明
DECLARE cursor_name CURSOR [WITH HOLD]
FOR sql_statement
语法 2:使用 已声明的 PREPARED_ID 来进行 CURSOR 声明
DECLARE cursor_name CURSOR [WITH HOLD]
FOR prepared_id
语法 3:使用 已知的 STRING 语句 进行 CURSOR 声明
DECLARE cursor_name CURSOR [WITH HOLD]
FROM string-expression
FOREACH (LOOP) 概述
注:只能用于 Non_Scrolling Cursor
声明完 CURSOR 后即可用 FOREACH 进行将所有符合条件的数据一笔一笔的抓取出来处理,不需要 OPEN。
FOREACH 与 FETCH 的不同
FOREACH 具有循环处理的架构,而 FETCH 则必须配合 WHILE 循环一起用。
FOREACH 只能循序处理,而 FETCH 可做随机跳跃的选取。
执行 FETCH 前必须 OPEN,结束时 CLOSE 关闭并释放 CURSOR
**FOREACH 指令可自动开启与关闭 CURSOR**,无需手动 OPEN 和 CLOSE。
综合示例
LET l_sql = "SELECT * FROM employee_file", "WHERE", l_str
PREPARE emp_pre FROM l_sql
DECLARE emp_cus CURSOR FOR emp_pre # 使用 prepare_id 来声明 cursor
FOREACH emp_cus INTO l_emp.* #循序抓资料
IF l_emp.salary > 80000 THEN
EXIT FOREACH
END IF
END FOREACH
MAIN
DEFINE clist ARRAY[200] OF RECORD
cnum INTEGER,
cname CHAR(50)
END RECORD
DEFINE I INTEGER
DEFINE str STRING
DEFINE c_name CHAR(50)
DATABASE stores
LET c_name = ARG_VAL(1)
LET str = "SELECT customer_num, cust_name FROM customer WHERE cname = ?"
PREPARE prepare_id FROM str
DECLARE c1 CURSOR FOR prepare_id # 使用 prepare_id 来声明 cursor
LET i = 1
FOREACH c1 USING c_name INTO clist[i].*
LET i = i + 1
END FOREACH
DISPLAY "Number of rows found: ", i
END MAIN
[](
)数据的锁定
[](
)LOCKING CURSOR(DECLARE、OPEN、FETCH、CLOSE)
当要进行数据的修改 (UPDATE) 时,为防止多人同时修到同一笔数据,应当考虑在开始修改前进行 数据锁定(LOCK),以确保同时间只有一人能取得修改权,Genero FGL 中延续 INFORMIX 4GL 的作法,采用 LOCKING CURSOR 对数据进行锁定。
LOCKING CURSOR 也称 FOR UPDATE CURSOR。用于在数据更新程序段,将数据进行一个上锁的动作,以避免两组以上的联机同时再更新同一 TABLE 下的同一笔数据。如果未作 LOCK 的动作,可能再抓取数据的同时,有其他人正在进行数据修改。此 CURSOR 不属于数据查询的 CURSOR,而需列为更新的 CURSOR。
DECLARE cursor_name CURSOR FOR sql statement FOR UPDATE [NOWAIT]
OPEN cursor_id [USING value]
FETCH cursor_id INTO variable
CLOSE cursor_id
说明:通常运用在 Update 程序,做资料 Lock 的动作。
通过 DECLARE 定义
通过 OPEN 开启该 CURSOR
通过
FETCH cursor_name INTO 变量
抓取资料
DECLARE 概述
DECLARE cursor_name CURSOR FOR select_statement FOR UPDATE [NOWAIT]
此处与 SCROLL CURSOR 或 Non-SCROLL CURSOR 最大的差异在于 SQL 查询指令的
最后须加上FOR UPDATE
(ORACLE 数据库需再加上 NOWAIT
),以标明此 CURSOR 为 LOCKING CURSOR。
此处亦可使用 FROM char_variable 方式来定义 SQL 查询指令。
OPEN 概述
OPEN cursor_id
FETCH 概述
FETCH cursor_id INTO program_variable
此指令除从数据库中取得数据外,在 LOCKING CURSOR 的状态下,还会将所抓取到的数据锁住,直到程序执行
CLOSE cursor_id
的指令才会释放。
CLOSE 概述
CLOSE cursor_id
关闭并释放 CURSOR,待释放完成后,系统才会将被锁定的数据释放。
综合案例
LET l_sql = "SELECT * FROM employee_file",
"WHERE no = ? FOR UPDATE"
PREPARE emp_pre FROM l_sql
DECLARE emp_cl CURSOR FOR emp_pre
OPEN emp_cus USING l_no
FETCH emp_cus INTO l_emp.* #只抓一笔资料 lock
DATABASE ds
MAIN
DEFINE g_gav01 LIKE gav_file.gav01
DEFINE g_gav08 LIKE gav_file.gav08
LET g_forupd_sql = "SELECT * from gav_file WHERE gav01=? AND gav08=? ",
"FOR UPDATE"
DECLARE p_per_lock_u CURSOR FROM g_forupd_sql
OPEN p_per_lock_u USING g_gav01,g_gav08
IF STATUS THEN
CLOSE p_per_lock_u
RETURN
END IF
FETCH p_per_lock_u INTO g_gav_lock.*
IF SQLCA.sqlcode THEN
CLOSE p_per_lock_u
RETURN
END IF
CLOSE p_per_lock_u
END MAIN
[](
)USING 的使用时机
此处的『USING』和之前关于 变量格式输出的 USING 意义不同。
在组成查询的 SQL 指令时,有时一开始不知道要查询的数据是什么 ,因此『可在 SQL 查询指令中使用问号 ?
,后续要使用 CURSOR 时,再将已知值用 USING 传入』。
说明
SQL 语句中可以定义多个问号
?
;使用 USING 给值时需依序对应,并用逗号隔开USING 必需跟在 OPEN 后 (Scroll Cursor 及 Locking Cursor 种)、FOREACH 后 (Nonscroll Cursor) 或 EXECUTE 指令后 (大量执行 SQL Cursor)
前面的案例中都用到了 USING。
[](
)TRANSACTION:事务控制
说明:需要多表格的同时连动时,可采用 TRANSACTION 作法。
通过
BEGIN WORK
声明 TRANSACTION 开始执行 INSERT、UPDATE、DELETE 等指令
通过
COMMIT WORK
或ROLLBACK WORK
声明 TRANSACTION 结束
注意
BEGIN WORK
开始后,一定要有COMMIT WORK
或ROLLBACK WORK
也就是必须做出数据是否写入的判断
TRANSACTION 区中的程序尽量不要太长,以免影响需要调用同笔数据的其他用户
(但使用者本身不受影响,未 COMMIT WORK 前仍可调用已变更数据)
有些 DDL 指令 (如
CREATE TABLE
) 会有自动COMMIT WORK
功能当
COMMIT WORK
或ROLLBACK WORK
时,会自动关闭未声明『WITH HOLD』的 CURSOR
BEGIN WORK
...
[INSERT ...]
评论