PL / SQL的基本结构
PL / SQL的基本结构
PL / SQL代表Procedural Language / SQL。PL / SQL通过添加过程语言中的构造来扩展SQL,从而产生比SQL更强大的结构语言。PL / SQL中的基本单元是一个块。所有PL / SQL程序都由块组成,这些块可以相互嵌套。通常,每个块在程序中执行逻辑操作。块具有以下结构:
DECLARE/ *声明部分:变量,类型和本地子程序。* /BEGIN/ *可执行部分:过程和SQL语句都在这里。* // *这是块中唯一需要的部分。* /EXCEPTION/ *异常处理部分:错误处理语句在这里。* / END;
只需要可执行部分。其他部分是可选的。PL / SQL程序中允许的唯一SQL语句是SELECT, INSERT, UPDATE,DELETE和其他几个数据操作语句以及一些事务控制。但是,SELECT语句有一个特殊的形式,其中一个元组放在变量中; 稍后会详细介绍。不允许使用CREATE,DROP或ALTER等数据定义语句。可执行部分还包含诸如赋值,分支,循环,过程调用和触发器之类的构造,这些构造如下所述(触发器除外))。PL / SQL不区分大小写。可以使用C样式注释(/ * ... * /)。
要执行PL / SQL程序,我们必须遵循程序文本本身
- 带有单个点(“ 。 ”)的行,然后
- 一条带跑步的线;
与Oracle SQL程序一样,我们可以通过在sqlplus中键入PL / SQL程序或将代码放入文件并以我们在Oracle入门中学习的各种方式调用文件来调用PL / SQL程序。
变量和类型
变量和类型信息通过变量在PL / SQL程序和数据库之间传输 。每个变量都有一个与之关联的特定类型。那种类型可以
- SQL用于数据库列的类型之一
- PL / SQL中使用的泛型类型,例如NUMBER
- 声明与某些数据库列的类型相同
最常用的泛型类型是NUMBER。NUMBER类型的变量 可以包含整数或实数。最常用的字符串类型是VARCHAR(n ),其中 n是字符串的最大长度(以字节为单位)。此长度是必需的,没有默认值。例如,我们可能会声明:
DECLAREprice NUMBER;myBeer VARCHAR(20);
请注意,PL / SQL允许BOOLEAN变量,即使Oracle不支持BOOLEAN作为数据库列的类型。
PL / SQL中的类型可能很棘手。在许多情况下,PL / SQL变量将用于处理存在于现有关系中的数据。在这种情况下,变量必须与关系列具有相同的类型。如果存在任何类型不匹配,则变量赋值和比较可能无法按预期方式工作。为了安全起见,您应该使用%TYPE运算符,而不是硬编码变量的类型。例如:
DECLAREmyBeer Beers.name%TYPE;
给出了PL / SQL变量myBeer,无论为Beers中的name 列声明了什么类型 。
变量也可以具有包含多个字段的记录类型。声明此类变量的最简单方法是 在关系名称上使用%ROWTYPE。结果是一种记录类型,其中字段与关系的属性具有相同的名称和类型。例如:
DECLAREbeerTuple Beers%ROWTYPE;
使变量beerTuple成为具有字段名称 和制造的记录,假设该关系具有模式Beers(名称,制造商)。
任何变量的初始值,无论其类型如何,都是NULL。我们可以使用“ := ”运算符为变量赋值。赋值可以在声明变量的类型之后立即发生,也可以在程序的可执行部分中的任何位置发生。一个例子:
DECLAREa NUMBER := 3;BEGINa := a + 1;END;.run;
此程序在运行时无效,因为数据库没有任何更改。
PL / SQL中的简单程序最简单的程序形式有一些声明,后跟一个可执行部分,它由一个或多个我们熟悉的SQL语句组成。主要的细微差别是SELECT语句的形式与其SQL形式不同。在SELECT子句之后,我们必须 有一个INTO子句列出变量,一个用于SELECT子句中的每个属性,其中必须放置检索到的元组的组件。
注意我们说“元组”而不是“元组”,因为 PL / SQL中的SELECT语句只有在查询结果包含单个元组时才有效。与嵌入式SQL相关的情况基本上与本文第7.1.5节中讨论的“单行选择”的情况相同。如果查询返回多个元组,则需要使用游标,如下一节所述。这是一个例子:
CREATE TABLE T1(e INTEGER,f INTEGER);DELETE FROM T1;INSERT INTO T1 VALUES(1, 3);INSERT INTO T1 VALUES(2, 4);/* Above is plain SQL; below is the PL/SQL program. */DECLAREa NUMBER;b NUMBER;BEGINSELECT e,f INTO a,b FROM T1 WHERE e>1;INSERT INTO T1 VALUES(b,a);END;.run;
幸运的是,只有一个T1的元组具有大于1的第一个分量,即(2,4)。因此INSERT语句将(4,2)插入到T1中。
PL / SQL中的控制流程
PL / SQL中的控制流程PL / SQL允许您以相当熟悉的方式分支和创建循环。
1.条件控制
一个IF语句看起来象:
IF <condition> THEN <statement_list> ELSE <statement_list> END IF;
该ELSE部分是可选的。如果您想要一个多路分支,请使用:
IF <condition_1> THEN ...ELSIF <condition_2> THEN ...... ...ELSIF <condition_n> THEN ...ELSE ...END IF;
以下是一个示例,稍微修改了上一个,现在我们只在第二个组件为1时才进行插入。如果不是,我们首先向每个组件添加10,然后插入:
DECLAREa NUMBER;b NUMBER;BEGINSELECT e,f INTO a,b FROM T1 WHERE e>1;IF b=1 THENINSERT INTO T1 VALUES(b,a);ELSEINSERT INTO T1 VALUES(b+10,a+10);END IF;END;.run;
2.循环控制
使用以下内容创建循环:
LOOP<loop_body> /* A list of statements. */END LOOP;
<loop_body>中的 至少一个语句应该是 表单的 EXIT语句
EXIT WHEN <condition>;
如果<condition>为true,则循环中断。例如,这里有一种方法将每对(1,1)到(100,100)插入 上述两个例子的T1中:
DECLAREi NUMBER := 1;BEGINLOOPINSERT INTO T1 VALUES(i,i);i := i+1;EXIT WHEN i>100;END LOOP;END;.run;
一些其他有用的循环形成语句是:
WHILE <condition> LOOP<loop_body>END LOOP;FOR <var> IN <start>..<finish> LOOP<loop_body>END LOOP;
- EXIT本身就是一个无条件的循环中断。如果您愿意,可以在条件内使用它。
- 加WHILE循环可形成
- 可以形成 一个简单的FOR循环:
- 这里,<var>可以是任何变量; 它是for循环的本地,不需要声明。此外,<start>和<finish> 是常量。
游标
游标是通过一些关系的元组运行的变量。这种关系可以是存储表,也可以是某些查询的答案。通过将关系中的每个元组提取到游标中,我们可以编写一个程序来读取和处理每个这样的元组的值。如果存储了关系,我们还可以更新或删除当前光标位置的元组。
下面的示例说明了一个游标循环。它使用我们的示例关系 T1(e,f), 其元组是整数对。程序将删除第一个组件小于第二个组件的每个元组,并将反向元组插入T1。
1) DECLARE/ *用于保存查询结果的输出变量:* / 2) a T1.e%TYPE;3) b T1.f%TYPE;/ *光标声明:* / 4) CURSOR T1Cursor IS5) SELECT e, f6) FROM T17) WHERE e < f8) FOR UPDATE;9) BEGIN10) OPEN T1Cursor;11) LOOP/ *将上述查询结果的每一行检索到PL / SQL变量中:* / 12) FETCH T1Cursor INTO a, b;/ *如果没有要获取的行,退出循环:* / 13) EXIT WHEN T1Cursor%NOTFOUND;/ *删除当前元组:* / 14) DELETE FROM T1 WHERE CURRENT OF T1Cursor;/ *插入反向元组:* / 15) INSERT INTO T1 VALUES(b, a);16) END LOOP;/ *查询使用的免费游标。* / 17) CLOSE T1Cursor;18) END;19) .20) run;
以下是该计划各行的解释:
- 第(1)行介绍了声明部分。
- 第(2)和(3)行声明变量a和b的类型等于关系 T1的属性e和f的类型。虽然我们知道这些类型是INTEGER,但我们明智地确保它们可能具有的任何类型都被复制到PL / SQL变量(与前面的示例相比,我们不那么小心并且声明相应的变量是NUMBER类型)。
- 第(4)到(8)行定义了光标T1Cursor。它的范围超出SELECT - FROM - WHERE 查询定义的关系。该查询选择T1的元组,其第一个组件小于第二个组件。第(8)行声明游标FOR UPDATE,因为稍后我们将使用此游标在第(14)行修改T1。通常,如果光标不用于修改,则不需要FOR UPDATE。
- 第(9)行开始程序的可执行部分。
- 第(10)行打开光标,这是必不可少的步骤。
- 行(11)到(16)是PL / SQL循环。请注意,这样的循环由LOOP和END LOOP括起来。在循环内我们发现:
- 在Line(12)上,通过游标获取到局部变量。通常,FETCH语句必须为检索到的元组的每个组件提供变量。由于Lines(5)到(7)的查询产生了对,我们已经正确地提供了两个变量,并且我们知道它们的类型正确。
- 在线(13),测试环路断开条件。它的含义应该是明确的:当游标的提取无法找到更多的元组时,游标名称后的%NOTFOUND是真的。
- 在行 (14)上,SQL DELETE语句使用特殊的WHERE条件CURRENT OF T1Cursor删除当前元组。
- 在行(15)上,一个SQL 反馈元组插入T1的SQL INSERT语句。
- 第(17)行关闭光标。
- 第(18)行结束PL / SQL程序。
- 第(19)行和第(20)行导致程序执行。
存储过程
程序PL / SQL过程的行为与其他编程语言中的过程非常相似。下面是一个PL / SQL过程addtuple1的示例,给定一个整数i,将元组(i,'xxx')插入以下示例关系中:
CREATE TABLE T2 (a INTEGER,b CHAR(10));CREATE PROCEDURE addtuple1(i IN NUMBER) ASBEGININSERT INTO T2 VALUES(i, 'xxx');END addtuple1;.run;
关键字CREATE PROCEDURE后跟过程名称及其参数引入过程。一个选项是 通过OR REPLACE跟随CREATE。这样做的好处是,如果您已经完成了定义,那么您将不会收到错误。另一方面,如果先前的定义是同一个名称的不同过程,则不会发出警告,旧过程将丢失。
可以有任意数量的参数,每个参数后跟一个模式 和一个类型。可能的模式是IN(只读),OUT (只写)和INOUT(读和写)。注意:与PL / SQL变量声明中的类型说明符不同,参数声明中的类型说明符必须不受约束。例如,CHAR(10) 和VARCHAR(20)是非法的; 应该使用CHAR或VARCHAR。参数的实际长度取决于调用过程时传入的相应参数。
参数后面是关键字AS(IS是同义词)。然后是主体,它本质上是一个PL / SQL块。我们在END之后重复了过程的名称,但这是可选的。然而,DECLARE部分应不与关键字开始DECLARE。相反,遵循AS,我们有:
... AS<local_var_declarations>BEGIN<procedure_body>END;.run;
将运行在最后运行该语句创建的程序; 它不执行该程序。要执行该过程,请使用另一个PL / SQL语句,其中该过程作为可执行语句调用。例如:
BEGIN addtuple1(99); END;.run;
以下过程还将一个元组插入到T2中,但它将两个组件作为参数:
CREATE PROCEDURE addtuple2(x T2.a%TYPE,y T2.b%TYPE)ASBEGININSERT INTO T2(a, b)VALUES(x, y);END addtuple2;.run;
现在,要向T2添加元组(10,'abc'):
BEGINaddtuple2(10, 'abc');END;.run;
以下说明使用OUT参数:
CREATE TABLE T3 (a INTEGER,b INTEGER);CREATE PROCEDURE addtuple3(a NUMBER, b OUT NUMBER)ASBEGINb := 4;INSERT INTO T3 VALUES(a, b);END;.run;DECLAREv NUMBER;BEGINaddtuple3(10, v);END;.run;
请注意,为声明为OUT或INOUT的参数赋值 会导致写入相应的输入参数。因此,OUT或INOUT参数的输入参数应该是具有“左值”的值,例如上面示例中的v之类的变量。对于OUT / INOUT参数,不应传入常量或文字参数。
我们也可以编写函数而不是程序。在函数声明中,我们按RETURN参数列表和返回值的类型:
CREATE FUNCTION <func_name>(<param_list>)RETURN <return_type> AS ...
在函数定义的主体中,“ RETURN <expression> ;” 退出函数并返回<expression>的值。
要找出您创建的过程和函数,请使用以下SQL查询:
select object_type, object_namefrom user_objectswhere object_type = 'PROCEDURE'or object_type = 'FUNCTION';
删除存储过程/函数:
drop procedure <procedure_name>;drop function <function_name>;
发现错误PL / SQL并不总是告诉您有关编译错误的信息。相反,它会给你一个神秘的信息,例如“使用编译错误创建的过程”。如果您没有立即看到错误,请尝试发出命令
show errors procedure <procedure_name>;
或者,您可以键入SHO ERR(SHOW ERRORS的缩写)以查看最新的编译错误。
请注意,作为错误消息的一部分给出的错误的位置并不总是准确的!
打印变量有时我们可能想要打印PL / SQL局部变量的值。一种“快速而又脏”的方式是将它存储为某种关系的唯一元组,并在PL / SQL语句打印出与SELECT 语句的关系之后。更流行的方法是定义一个绑定变量,这是唯一可以使用print命令打印的类型。绑定变量是必须在PL / SQL语句中以冒号作为前缀的类型,例如:关于触发器一节中讨论的new。
VARIABLE <name> <type>
PRINT :<name>;
- 我们声明一个绑定变量如下:
- 其中类型只能是三件事之一:NUMBER,CHAR或CHAR(n)。
- 然后我们可以在后面的PL / SQL语句中为变量赋值,但是我们必须在冒号前面添加冒号。
- 最后,我们可以执行一个声明
- 在PL / SQL语句之外
VARIABLE x NUMBERBEGIN:x := 1;END;.run;PRINT :x;
出处:http://infolab.stanford.edu/~ullman/fcdb/oracle/or-plsql.html
PL / SQL的基本结构相关推荐
- PL/SQL Developer 导出表结构和表数据
导出表结构 打开PL/SQL Developer,选择tables 点击菜单栏Tools,选择Export User Objects 出现下面的窗口 导出后是一个sql文件. 导出表数据 一般情况下可 ...
- PL/SQL基础:结构、变量处理——PL/SQL教程(一)
什么是PL/SQL 许多时候我们会利用结构化查询语言(SQL)来访问和操作关系型数据库.这种语言的特点就是非过程化.也就是说使用的时候不用指明执行的具体方法和途径,即不用关注任何的实现细节.但这种 ...
- Oracle数据库之PL/SQL程序基础设计
一.PL/SQL块结构 前边我们已经介绍了PL/SQL块的结构,再来回顾一下: DECLARE /** 声明部分--定义常量.变量.复杂数据类型.游标.用户自定义异常*/ BEGIN /** 执行部分 ...
- oracle if函数变量,Oracle数据库——PL/SQL编程
PL/SQL块基本结构 declare -- 声明部分 begin -- 执行部分 exception -- 异常处理部分 end; 声明部分:包含变量.常量定义,由 declare 关键字开始,如果 ...
- PL/SQL块结构和组成元素
本篇主要内容如下: 2.1 PL/SQL块 2.2 PL/SQL结构 2.3 标识符 2.4 PL/SQL 变量类型 2.4.1 变量类型 2.4.2 复合类型 2.4.2.1 记 ...
- PL/SQL 处理流程
P249 -P254 oracle8i_9i数据库基础--查看本号百度文库 ***********PL/SQL 简介*************** 1.PL/SQL 是过程语言(Procedural ...
- Oracle入门(十四.1)之PL / SQL简介
一.PL / SQL描述 程序语言扩展到SQL: •允许将基本程序逻辑和控制流与SQL语句组合在一起. •是Oracle专有编程语言. - 它只能用于Oracle数据库或工具. 二.程序语言扩展到SQ ...
- PL/SQL编程基本概念
/* =============================================================================pl/sql编程 =========== ...
- [顶]ORACLE PL/SQL编程详解之二:PL/SQL块结构和组成元素(为山九仞,岂一日之功)...
[顶]ORACLE PL/SQL编程详解之二:PL/SQL块结构和组成元素(为山九仞,岂一日之功) 原文:[顶]ORACLE PL/SQL编程详解之二:PL/SQL块结构和组成元素(为山九仞,岂一日之 ...
最新文章
- teamcity plugin中读取js和css文件的方法
- linux c++ 目录操作,C++文件及文件夹操作整理(代码示例)
- 2014新跟踪算法KCF笔记
- 【Ubuntu入门到精通系列讲解】常用 Linux 命令的基本使用
- Arduino ESP8266编程深入要点
- 东莞电子计算机学校,东莞市电子科技学校
- win10 hyper-v 虚拟机ping不通宿主机问题
- C# ASP.NET MVC 图片上传的多种方式(存储至服务器文件夹,阿里云oss)
- Linux 主机超全渗透测试命令汇总
- 人工智障学习笔记——机器学习(5)朴素贝叶斯
- qt 正则 html,Qt 正则表达式 (一)
- vim下中文乱码问题解决办法
- php 有几种打印方法,php 5种打印方式及变量类型,
- Value-Decomposition Networks For Cooperative Multi-Agent Learning(VDN)
- 米思齐(Mixly)图形化系列教程(三)-变量
- 【MindSpore易点通机器人-01】你也许见过很多知识问答机器人,但这个有点不一样
- Mockplus组件样式库一键解决风格复用
- html怎么直接修改,如何编辑运行HTML网页文件(HTML编辑工具使用介绍)
- R语言 Holt-Winters法
- oracle operation_type,案例:Oracle报错performing DML/DDL operation over object in bin解决办法
热门文章
- 关于使用字库-雅黑字体(msyh.ttf )显示中文的一些。。。
- u盘linux系统 隐藏文件,怎么样将u盘中隐藏的文件找出来
- 精尽 JDK 源码解析 —— 集合(七)TreeSet
- 计算机硕士论文参考文献,计算机硕士研究生方面论文参考文献 计算机硕士研究生论文参考文献哪里找...
- Container容器
- ABP Quartz.NET “最佳“实践-2 执行任务
- Eye in hand And eye on hand calibration
- CRM(客户关系管理)应用与理论研究综述
- Markdown 写作注意事项
- unexpected output in sfdisk --version [sfdisk,来自 util-linux 2.23.2]后端盘问题