注:如果不熟悉Db2存储过程的基本概念和HelloWorld例子,请参考我另一篇文档( https://blog.csdn.net/duke_ding2/article/details/124873609 )。

环境

  • 操作系统:Ubuntu 20.04
  • Db2:11.5.0.0

SQL PL简介

SQL过程语言(SQL Procedural Language)是SQL的语言扩展,由“可以在SQL语句中实现过程逻辑的语句和语言元素”组成,比如声明变量、条件判断、变量赋值等。

SQL PL主要用于SQL存储过程。在SQL存储过程中可使用SQL PL全集。

先来看一个简单例子。创建文件 test3.sql 如下:

create or replace procedure test3(in score int)language sql
beginif score < 60 thencall dbms_output.put_line('Fail');elseif score >= 60 and score < 80 thencall dbms_output.put_line('Pass');elsecall dbms_output.put_line('Outstanding');end if;
end@set serveroutput on@call test3(70)@set serveroutput off@

运行脚本,如下:

➜  temp0523 db2 -td@ -f test3.sql
DB20000I  The SQL command completed successfully.DB20000I  The SET SERVEROUTPUT command completed successfully.Return Status = 0PassDB20000I  The SET SERVEROUTPUT command completed successfully.

本例中,使用了条件判断,根据不同的 score 值,输出相应的结果。

Inline SQL PL

Inline SQL PL是SQL PL的子集,用于inline复合语句。

复合语句

所谓复合语句,说白了就是把多个语句用 begin/end (或者 begin atomic/end )包起来。

复合语句又可分为两种:

  • Inline复合语句:用 begin atomic/end 包起来,顾名思义,它是原子的。可以包含inline SQL PL(前面提到,是SQL PL的子集);
  • Compiled复合语句:用 begin/end 包起来,非原子性。可以包含所有的SQL PL;

复合语句可以单独运行,也可以包含在数据库对象定义(比如存储过程、函数)中。

创建文件 test1.sql 如下:

begindeclare a, b varchar(100);set a = (select * from sysibm.sysdummy1);select * into a from sysibm.sysdummy1;
end@

运行脚本,如下:

➜  temp0523 db2 -td@ -f test1.sql
DB20000I  The SQL command completed successfully.

创建文件 test2.sql 如下:

begin atomicdeclare a, b varchar(100);set a = (select * from sysibm.sysdummy1);-- select * into a from sysibm.sysdummy1;
end@

运行脚本,如下:

➜  temp0523 db2 -td@ -f test2.sql
DB20000I  The SQL command completed successfully.

注意本例中被注释的代码,它在inline复合语句中会报错,这难道就是因为前面所提到的,inline SQL PL是SQL PL的子集,所以有些功能不支持?

SQL例程

所谓SQL例程,就是只包含SQL语句和SQL PL语句的例程。和例程的分类相似,SQL例程可分为SQL存储过程、SQL函数、SQL方法。本文中只涉及SQL存储过程。

关于创建SQL例程的语法,请参考 https://www.ibm.com/docs/en/db2/11.5?topic=statements-create-procedure-sql 。

该文档中有一个具体例子:

   CREATE PROCEDURE MEDIAN_RESULT_SET (OUT medianSalary DOUBLE)RESULT SETS 1LANGUAGE SQLBEGINDECLARE v_numRecords INT DEFAULT 1;DECLARE v_counter INT DEFAULT 0;DECLARE c1 CURSOR FORSELECT CAST(salary AS DOUBLE)FROM staffORDER BY salary;DECLARE c2 CURSOR WITH RETURN FORSELECT name, job, CAST(salary AS INTEGER)FROM staffWHERE salary > medianSalaryORDER BY salary;DECLARE EXIT HANDLER FOR NOT FOUNDSET medianSalary = 6666;SET medianSalary = 0;SELECT COUNT(*) INTO v_numRecordsFROM STAFF;OPEN c1;WHILE v_counter < (v_numRecords / 2 + 1)DOFETCH c1 INTO medianSalary;SET v_counter = v_counter + 1;END WHILE;CLOSE c1;OPEN c2;END

我们从该例子看一下SQL存储过程的大致结构:

  • CREATE PROCEDURE MEDIAN_RESULT_SET :我一般会用 create or replace ,免得多次运行时报错;
  • (OUT medianSalary DOUBLE) :参数列表,本例中只有一个out参数;
  • RESULT SETS 1 :可选项,表示返回多少个result set,默认是0;
  • LANGUAGE SQL :可选项,表示SQL存储过程,是默认选项;
  • BEGIN ... END :SQL存储过程的最核心就是一个复合语句。前面提到,复合语句是用 begin/end (或者 begin atomic/end )所包含的多条语句。

注:本例中只用到了2个选项,其它还有很多选项,具体用法请参考官方文档。

如果连接的是 sample 数据库,则 staff 表和里面的数据都已经准备好了,可以直接运行该存储过程,看一下效果。

新建 test4.sql 文件,对上面内容稍作修改:

  • 加上 OR REPLACE ,以免多次运行时报错;
  • 加上 call MEDIAN_RESULT_SET(?) ,调用该存储过程;
  • 加上 @ 结束符;

如下:

   CREATE OR REPLACE PROCEDURE MEDIAN_RESULT_SET (OUT medianSalary DOUBLE)RESULT SETS 1LANGUAGE SQLBEGINDECLARE v_numRecords INT DEFAULT 1;DECLARE v_counter INT DEFAULT 0;DECLARE c1 CURSOR FORSELECT CAST(salary AS DOUBLE)FROM staffORDER BY salary;DECLARE c2 CURSOR WITH RETURN FORSELECT name, job, CAST(salary AS INTEGER)FROM staffWHERE salary > medianSalaryORDER BY salary;DECLARE EXIT HANDLER FOR NOT FOUNDSET medianSalary = 6666;SET medianSalary = 0;SELECT COUNT(*) INTO v_numRecordsFROM STAFF;OPEN c1;WHILE v_counter < (v_numRecords / 2 + 1)DOFETCH c1 INTO medianSalary;SET v_counter = v_counter + 1;END WHILE;CLOSE c1;OPEN c2;END@call MEDIAN_RESULT_SET(?)@

运行 test4.sql 脚本,如下:

➜  temp0523 db2 -td@ -f test4.sql
DB20000I  The SQL command completed successfully.Value of output parameters--------------------------Parameter Name  : MEDIANSALARYParameter Value : +7.68582000000000E+004Result set 1--------------NAME      JOB   3          --------- ----- -----------Marenghi  Mgr         77506O'Brien   Sales       78006Pernal    Sales       78171Plotz     Mgr         78352Wilson    Sales       78674Daniels   Mgr         79260Williams  Sales       79456Hanes     Mgr         80659Jones     Mgr         81234Molinare  Mgr         82959Lundquist Clerk       83369Smith     Sales       87654Lea       Mgr         88555Quill     Mgr         89818Lu        Mgr         90010Fraye     Mgr         91150Sanders   Mgr         9835717 record(s) selected.Return Status = 0

可见:

  • 通过out参数 medianSalary ,输出了中位数工资的值: +7.68582000000000E+004staff 表中共有35条记录,按工资排序的第18条记录,就是中位数工资);
  • 通过游标 c2 ,输出了所有大于中位数工资的记录,包括姓名、工作、工资;

下面我们重点来看SQL存储过程的主体,也就是 begin/end (或者 begin atomic/end )所包含的部分。

在主体中,又可包含多个复合语句。其格式如下:

  label:  BEGIN Variable declarationsCondition declarationsCursor declarationsCondition handler declarationsAssignment, flow of control, SQL statements and other compound statementsEND label

官网一个具体例子( https://www.ibm.com/docs/en/db2/11.5?topic=procedures-structure-sql ):

   CREATE PROCEDURE DEL_INV_FOR_PROD (IN prod INT, OUT err_buffer VARCHAR(128))LANGUAGE SQLDYNAMIC RESULT SETS 1BEGINDECLARE SQLSTATE CHAR(5) DEFAULT '00000';DECLARE SQLCODE integer DEFAULT 0;DECLARE NO_TABLE CONDITION FOR SQLSTATE '42704';DECLARE cur1 CURSOR WITH RETURN TO CALLER  FOR SELECT * FROM Inv;A: BEGIN ATOMICDECLARE EXIT HANDLER FOR NO_TABLEBEGINSET ERR_BUFFER='Table Inv does not exist';END;SET err_buffer = '';IF (prod < 200)DELETE FROM Inv WHERE product = prod;ELSE IF (prod < 400)UPDATE Inv SET quantity = 0 WHERE product = prod;ELSEUPDATE Inv SET quantity = NULL WHERE product = prod; END IF;END A;B:  OPEN cur1;END

但是该例子貌似有语法错误…… if 后面不需要 then 吗?

atomic和not atomic

首先创建表 C1_SCHED

create table C1_SCHED(class_code varchar(100), day int)

注:不知道为啥,文档中这几个例子并没有对应sample DB的表,只好自己创建了。

创建 test6.sql 文件如下:

  CREATE or replace PROCEDURE not_atomic_proc ()   LANGUAGE SQL   SPECIFIC not_atomic_procnap:  BEGIN NOT ATOMIC            INSERT INTO c1_sched (class_code, day)VALUES ('R11:TAA', 1);           commit;SIGNAL SQLSTATE '70000';   INSERT INTO c1_sched (class_code, day)               VALUES ('R22:TBB', 1);    commit;END nap@call not_atomic_proc@

本例中, signal 用于触发错误,我理解有点类似于Java中的 throw

运行 test6.sql 脚本文件,如下:

➜  temp0523 db2 -td@ -f test6.sql
DB20000I  The SQL command completed successfully.SQL0438N  Application raised error or warning with diagnostic text: "".
SQLSTATE=70000➜  temp0523 echo $?
4

本例中,两个insert语句之间出现了错误,由于是 not atomic ,第一个insert语句并不会受影响,因为在出现错误之前就已经显式commit了。所以,虽然存储过程整体运行失败,但第一个insert语句已经成功了。

注意:如果去掉commit,则出现错误时,虽然第一个insert语句并不会立刻回滚,但是因为没有错误处理,所以最终存储过程失败后,第一个insert语句也会回滚。

创建 test7.sql 文件如下:

  CREATE or replace PROCEDURE atomic_proc ()LANGUAGE SQL  SPECIFIC atomic_proc  ap:  BEGIN ATOMIC            INSERT INTO c1_sched (class_code, day)     VALUES ('R33:TCC', 1);           --commit;SIGNAL SQLSTATE '70000';       INSERT INTO c1_sched (class_code, day)               VALUES ('R44:TDD', 1);    -- commit;END ap@call atomic_proc@

运行 test7.sql 脚本文件,如下:

➜  temp0523 db2 -td@ -f test7.sql
DB20000I  The SQL command completed successfully.SQL0438N  Application raised error or warning with diagnostic text: "".
SQLSTATE=70000

由于是 atomic ,所以出现错误时,第一个insert语句会立即回滚。

注意:在inline复合语句中不允许使用 SAVEPOINTCOMMITROLLBACK 等事务控制语句。

Db2自带的示例

请参考IBM官网 https://www.ibm.com/docs/en/db2/11.5?topic=samples-sample-files 。

在安装Db2时,在安装目录下(比如 /opt/ibm/db2/V11.5/ )有一个 samples 目录,里面有很多示例。其中有一个 sqlpl 目录,里面是SQL PL的示例。

这些示例可以运行在 sample 数据库上。如果安装时没有创建 sample 数据库,可以随时用 db2sampl 命令来创建。

例如 loop.db2 文件:

-- skip lots of comment here
CREATE PROCEDURE loop_until_space(OUT counter INT)
LANGUAGE SQL
BEGINDECLARE v_firstnme VARCHAR(12);DECLARE v_midinit CHAR(1);DECLARE v_lastname VARCHAR(15);DECLARE v_counter SMALLINT DEFAULT 0;DECLARE c1 CURSOR FOR SELECT firstnme, midinit, lastname FROM employeeORDER BY midinit DESC;DECLARE CONTINUE HANDLER FOR NOT FOUNDSET counter = -1;-- initialize OUT parameterSET counter = 0;OPEN c1;fetch_loop:LOOPFETCH c1 INTO v_firstnme, v_midinit, v_lastname;-- Use a local variable for the iterator variable-- because SQL procedures only allow you to assign -- values to an OUT parameterSET v_counter = v_counter + 1;IF v_midinit = ' ' THENLEAVE fetch_loop;END IF;END LOOP fetch_loop;CLOSE c1;-- Now assign the value of the local-- variable to the OUT parameterSET counter = v_counter;
END @

我们来运行一下 loop.db2 脚本:

➜  sqlpl db2 -td@ -f loop.db2
DB20000I  The SQL command completed successfully.➜  sqlpl db2 "call loop_until_space(?)"Value of output parameters--------------------------Parameter Name  : COUNTERParameter Value : 36Return Status = 0

注:示例代码中都是 create procedure 而不是 create or replace procedure ,所以只能运行一次……不太明白为何不用后者呢。

参考

  • https://www.ibm.com/docs/en/db2/11.5?topic=data-developing-routines
  • https://www.ibm.com/docs/zh/db2/11.5?topic=data-developing-routines (中文版)

Db2 SQL PL简介相关推荐

  1. Db2 SQL PL中的控制语句

    我们知道,代码流程控制中,最常见的三种逻辑结构是顺序.选择.循环. 顺序就不用说了,我们重点看一下SQL PL中的选择和循环,以及其它流程控制语句. 环境 操作系统:Ubuntu 20.04 Db2: ...

  2. PL/SQL程序设计(一)—— PL/SQL程序设计简介

    (一)什么是PL/SQL PL/SQL是是由甲骨文公司在90年代初开发,以提高SQL的功能. PL/SQL是嵌入在Oracle数据库中的三个关键的编程语言之一(随着SQL本身和Java).PL/SQL ...

  3. PL/SQL程序设计 第一章 PL/SQL 程序设计简介

    PL /SQL是一种高级数据库程序设计语言,该语言专门用于在各种环境下对ORACLE数据库进行访问.由于该语言集成于数据库服务器中,所以PL/SQL代码可以对数据进行快速高效的处理.除此之外,可以在O ...

  4. PL/SQL编程基础(一):PL/SQL语法简介(匿名PL/SQL块)

    PL/SQL PL/SQL是Oracle在关系数据库结构化查询语言SQL基础上扩展得到的一种过程化查询语言. SQL与编程语言之间的不同在于,SQL没有变量,SQL没有流程控制(分支,循环).而PL/ ...

  5. DB2 SQL性能调优秘笈pdf

    下载地址:网盘下载 简介 编辑 <DB2 SQL性能调优秘笈>是一本不可多得的DB2数据库性能调优秘笈,由拥有20余年DB2工作经验的资深数据库专家撰写,Amazon全五星评价畅销书.&l ...

  6. DB2 SQL性能调优秘笈

    <DB2 SQL性能调优秘笈> 基本信息 作者: (美)Tony Andrews 译者: 陈勇 杨健康 丛书名: 华章程序员书库 出版社:机械工业出版社 ISBN:978711142502 ...

  7. db2 sql 优化

    出处:http://www.ibm.com/developerworks/cn/data/library/techarticles/dm-0909querytuning/ 内容提要 通过 " ...

  8. DB2 SQL查询结果集自动编号、返回条数范围控制研究

    摘要: DB2 SQL语句实现查询的记录自动编号.并根据编号进一步实现记录范围控制.分页查询. 环境: IBM DB2 Universal V9.1 Windows XP Professional 要 ...

  9. DB2 sql复制error sqlcode2038

    最近生产机上db2 sql replication 的capture端进程总是自动退出,现已经第5次出现了. ibm的分析结果: 从日志来看Capture异常停止地原因应该是capture应用程序在申 ...

最新文章

  1. 查看linux机器是32位还是64位的方法
  2. 【周末阅读】5G时代新型基础设施建设白皮书
  3. 干货︱机器学习中防止过拟合的处理方法
  4. Linux 禁ping和开启ping操作
  5. 科大星云诗社动态20210813
  6. Linux 设备树 : 节点与属性的删除
  7. Python实战应用-Clumper库函数全解析
  8. 大学教授撰写诗歌引人思考:美好人生怎能终止在17岁?
  9. 如何为企业量身打造一套高可用系统?
  10. 深入研究微服务架构——第三部分
  11. c语言居中三角形乘法表,用C语言输出四种三角形的九九乘法表
  12. install opencv debian env
  13. [Swift]LeetCode609. 在系统中查找重复文件 | Find Duplicate File in System
  14. java 叠加层_java中不可选择的叠加层
  15. paip.c++ 进程间通信方法大总结
  16. 从eoeandroid换到CSDN-[回顾]
  17. Snort企业部署实战
  18. 计算机工资表2017,2017事业单位工资标准表
  19. 微信号名称乱码什么情况_换手率数据透露一强烈信号;微组合保持谨慎;新基建股票池跌多涨少情况不佳……...
  20. 课代表:ChatGPT及大模型专题研讨会

热门文章

  1. Lyapunov stability analysis、LaSalle’s invariance principle、Barbalat’s lemma
  2. 华为OWS平台和HEC服务浅见
  3. 流程变革,从推倒三座大山开始
  4. PHP 实现中文分词搜索功能
  5. Animated之基础篇-概述
  6. Oracle数据库备份与恢复命令
  7. EPLAN小知识——如何在菲尼克斯(PHEONIX)官网下载EPLAN部件
  8. 汉字转拼音工具JPinyin的介绍和使用示例
  9. 【智能零售】解读双11后的新零售趋势
  10. 好客租房153-地图找房模块功能分析