写点什么

【实习之 T100 开发】Genero FGL (TIPTOP4GL) 学习笔记,2021 金九银十

用户头像
极客good
关注
发布于: 刚刚


[【实习】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)可以运用在资料的查询


  1. SCROLLING CURSOR

  2. 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)


说明:通常用于 查询程序,可以 随即抓取资料


  1. 通过 DECLARE 定义

  2. 利用 OPEN 开启该 CURSOR


例:OPEN test01_cursor


  1. 通过 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


【一线大厂Java面试题解析+核心总结学习笔记+最新架构讲解视频+实战项目源码讲义】
浏览器打开:qq.cn.hn/FTf 免费领取
复制代码


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) 的方式。


  1. 通过 DECLARE 定义

  2. 利用 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。


FOREACHFETCH 的不同



  • 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 的动作。


  1. 通过 DECLARE 定义

  2. 通过 OPEN 开启该 CURSOR

  3. 通过 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 作法。


  1. 通过 BEGIN WORK 声明 TRANSACTION 开始

  2. 执行 INSERT、UPDATE、DELETE 等指令

  3. 通过 COMMIT WORKROLLBACK WORK 声明 TRANSACTION 结束


注意


  • BEGIN WORK 开始后,一定要有 COMMIT WORKROLLBACK WORK


也就是必须做出数据是否写入的判断


  • TRANSACTION 区中的程序尽量不要太长,以免影响需要调用同笔数据的其他用户


(但使用者本身不受影响,未 COMMIT WORK 前仍可调用已变更数据)


  • 有些 DDL 指令 (如 CREATE TABLE) 会有自动 COMMIT WORK 功能

  • COMMIT WORKROLLBACK WORK 时,会自动关闭未声明『WITH HOLD』的 CURSOR


BEGIN WORK


...


[INSERT ...]

用户头像

极客good

关注

还未添加个人签名 2021.03.18 加入

还未添加个人简介

评论

发布
暂无评论
【实习之T100开发】Genero FGL (TIPTOP4GL) 学习笔记,2021金九银十