您的位置:首页 > 数据库

存储过程、函数、包、触发器、sql优化

2018-02-02 16:11 176 查看

一、PL/SQL编程简介

1、块结构

块结构语法:
[declare 

declaration_statements

]

begin

executable_statements

[exception

exception_handling_statements

]

end ;

其中:

declaration_statements声明PL/SQL块其余部分使用的变量。
executable_statements是块中实际可执行的语句,其中可能包括执行诸如循环、条件逻辑等任务的语句
exception_handling_statements中的语句负责处理当块运行时可能发生的任何可执行错误。exception块是可选的


举例:

declare

v_width integer ;

v_height integer := 2 ;

v_area integer := 6;

begin

v_width := v_area / v_height;

dbms_output.put_line('v_width = ' || v_width) ;

exception

when zero_divide then

dbms_output.put_line('division by zero') ;

end;



2.变量和类型

变量在declare块中声明,例如:

v_width integer ;

还可以通过 %type 关键字来定义变量的类型,这个关键字告诉PL/SQL使用与表中指定列相同的类型,例如:

v_product_price products.price%type ;



3.条件逻辑

在 PL/SQL中,if、then、else、elsif和end if 等关键字用于执行条件逻辑:


if condition1 then

statements1

elsif condition2 then

statements2

else

statements3

end if ;

举例:

if v_count > 0 then

v_message := 'v_count is positive' ;

if v_area > 0 then

v_message := 'v_count and v_area are positie' ;

end if ; 

elsif v_count = 0 then

v_message := 'v_count is zero' ;

else

v_message := 'v_count is negative' ; 

end if ;

4.循环

①.简单循环

简单循环在显式结束之前会一直运行,简单循环的语法如下:

loop

statements

end loop ;



要结束简单循环,可以使用exit或exit when语句,exit语句立即结束循环,exit when语句在指定条件出现时结束循环,例如:

v_count := 0 ;

loop

v_counter := v_counter + 1 ; 

exit when v_counter = 5 ;

end loop ;



也可以使用continue或continue when语句结束循环的当前迭代。continue语句无条件结束循环的当前迭代,continue when语句则在满足特定条件时结束循环的当前迭代,然后继续执行下一个迭代,例如:

loop

v_counter := v_counter + 1 ;

if v_counter = 3 then 

continue ;

end if ; 

exit when v_counter = 5 ;

end loop ;



v_counter := 0 ;

loop

v_counter := v_counter



②.while循环

while循环在某个特定条件出现之前一直运行。语法如下:

while condition loop

statements

end loop ;



举例:

v_counter := 0 ;

while v_counter < 6 loop

v_counter := v_counter + 1 ;

end loop ;



③.for循环

for循环会运行预先确定的次数,可通过给循环变量指定下限和上限来确定循环运行的次数,然后,循环变量在每次循环中递增(或在反向循环中递减),语法如下:

for loop_variable in [reverse] lower_bound.. upper_bound loop

statements

end loop ;

其中:

loop_variable指定循环变量。可以将已经存在的变量用作循环变量,也可以让循环语句子句创建循环变量(当所指定的变量不存在时会发生这种情况)。循环变量的值在每一次循环中都增加(如果使用了reverse关键字,就减少)1
reverse指定在每一次循环中循环变量都会递减。循环变量先被初始化为其上限,然后在每一次循环中递减1,直至达到其下限
lower_bound指定循环的下限
upper_bound指定循环的上限


举例:

for v_counter2 in 1.. 5 loop 

dbms_output.put_line(v_counter2) ; 

end loop ; 



for v_counter2 reverse 1.. 5 loop

dbms_output.put_line(v_counter2) ;

end loop ; 

5.游标

可以使用游标(cursor)获取查询返回的行。使用游标时一般需要遵循以下5个步骤:

(1)、声明一些变量,用于保存一行的列值

(2)、声明游标,它包含一个查询

(3)、打开游标

(4)、一次从游标中获取一行,并将列值存储在步骤(1)声明的变量中。然后对这些变量执行某些操作,例如将他们显示在屏幕上、使用他们进行某种计算,等等

(5)、关闭游标

举例:

declare 

v_product_id products.product_id%type ;

v_name          products.name%type ; 

v_price           products.price%type ; 

cursor v_product_cursor is

select product_id, name, price from products order by product_id ; 

begin

open v_product_cursor

loop 

fetch v_product_cursor into v_product_id, v_name, v_price ; 

exit when v_product_cursor%notfound ; 

dbms_output.put_line('v_product_id = ' || v_product_id || ', v_name =
15ee3
' || v_name || ', v_price = ' || v_price) ;


end loop ;

close v_product_cursor ; 

end ;

①.游标与for循环

当使用for循环时,可以不显式地打开和关闭游标,for循环会自动执行这些操作

declare

cursor v_product_cursor is

select product_i, name, price from products order by product_id ;

begin

for v_product in v_product_cursor loop 

dbms_output.put_line('product_id = ' || v_product.product_id || ', name = ' || v_product.name || ', price = ' || v_product.price) ;

end loop ; 

end ; 

②.open-for语句

也可以对游标使用open-for语句,由于可以将游标分配给不同的查询,因此可以更加灵活地处理游标

declare

type t_product_cursor is ref cursor return products%rowtype ; 

v_product_cursor t_product_cursor ;

v_product products%rowtype ;

begin

open v_prouct_cursor for select * from products where product_id < 5 ;

loop 

fetch v_product_cursor into v_product;

exit when v_product_cursor%notfound;

dbms_output.put_line(

'product_id = ' || v_product.product_id ||

', name = ' || v_product.name || 

', price = ' || v_product.price ) ;

end loop ;

close v_product_cursor ; 

end ; 

其中:

ref cursor是指向游标的指针,类似于C++编程语言中的指针

③.无约束游标

前面介绍的游标都有具体返回类型,这些游标称为约束游标。约束游标的返回类型必须与游标运行的查询中的列相匹配。无约束游标没有返回类型,因此可以运行任何查询,例如:

declare

type t_cursor is ref cursor;

v_cursor t_cursor;

v_product products%rowtype;

v_customer customers%rowtype;

begin

open v_cursor for select * from products where product_id < 5 ;

loop

fetch v_cursor into v_product ; 

exit when v_cursor%notfound ;

dbms_output.put_line('product_id = ' || v_product.product_id ||

', name = ' || v_product.name || ', price = ' || v_product.price);

end loop ;

open v_cursor for select * from customers where customer_id < 3 ;

loop

fetch v_cursor into v_customer ;

exit when v_cursor%notfound ;

dbms_output.put_line(' customer_id = ' || v_customer.customer_id ||

', first_name = ' || v_customer.first_name || ', last_name = ' || v_customer.last_name) ;

end loop ;

close v_cursor ;

end ;

6.异常

7.存储过程

①.创建过程

语法如下:
create [or replace] procedure procedure_name
[(parameter_name [in | out | in out] type [, ...])]
{is | as}
begin

procedure_body

end procedure_name ;

其中:

or replace说明如果过程已经存在,就替换已有的过程
procedure_name指定过程名
parameter_name指定传递给过程的参数名。可以向过程传递多个参数
in | out | in out 定义了参数的模式,每一个参数口可以选择下列模式之一:

-- in 是参数的默认模式。这种模式定义的参数在程序运行的时候必须具有值,在过程体重不能改变in参数

的值

-- out 模式定义的参数在过程体内部赋值

-- in out 模式定义的参数在过程运行时可能已经具有值,并且在过程体中也可以修改此值

type 指定参数的类型
procedure_body包含过程的实际代码

举例:

create procedure update_product_price(

p_product_id in products.product_id%type ,

p_factor         in number

) as 

v_product_count integer ;

begin

select count(*) into v_product_count from products where product_id = p_product_id ;

if v_product_count = 1 then

update products

set price = price * p_factor

where product_id = p_product_id ; 

commit ;

end if ;

exception 

when others then 

rollback ;

end update_product_price ;

②.调用过程

可通过call语句运行或调用过程,例如:

call update_product_price(1 , 1.5) ;

在oracle database 11g已经以上版本中,可以使用命名表示法或混合表示法来传递参数,例如:

call update_product_price(p_factor => 1.3 , p_product_id => 2) ;

③.删除过程

drop procedure用于删除过程,例如:

drop procedure update_product_price ;

8.函数

①.创建函数

create [or replace] function function_name
[(parameter_name [in | out | in out] type [, ...])]
return type
{is | as}
begin

function_body

end function_name ;

其中:

or replace 表示如果函数已经存在,就替换现有的函数
function_name指定函数名
parameter_name指定传递给函数的参数名,可以向函数传递多个参数
in | out | in out 指定参数的模式
type 指定参数的类型
function_body包含函数的实际代码。函数体不像过程,它必须有返回值,类型在return子句中指定
举例:

create function circle_area(

p_radius in number

) return number as

v_pi number := 3.1415926

v_area number ;

begin

v_area := v_pi * power(p_radius, 2) ;

return v_area ;

end circle_area ;

create function average_product_price(

p_product_type_id in integer

) return number as 

v_areage_product_price number ;

begin

select avg(price) into v_areage_product_price from products where

product_type_id = p_product_type_id ;

return v_areage_product_price ;

end average_product_price ;

②.调用函数

可以像调用其他数据库内置函数那样调用自定义函数,例如:

select circle_area(2) from dual ;

select circle_area(p_radius => 4) from dual ;

③.删除函数

drop function circle_area ;

9.包

包通常由两个部分组成:规范和包体。包的规范列出可用的过程、函数、类型和对象。可以使所有的数据库用户都可以访问这些项,因此这些项称为公有项。规范中不包含构成这些过程和函数的代码,包体中才包含实际的代码。

包体中任何在规范中未列出的项对于这个包都是私有对象。私有项只能用在包体内

①.创建包的规范

create [or replace] package package_name

{is | as}

package_specification

end package_name ;

其中:

package_name 指定包名
package_specification列出了包用户可以使用的公共过程、函数、类型和对象
举例:

create package product_package as 

type t_ref_cursor is ref cursor ;

function get_products_ref_cursor return t_ref_cursor ;

procedure update_product_price(

p_product_id in products.product_id%type ,

p_factor         in number

) ;

end product_package ;

②.创建包体

create [or replace] package body package_name

{is | as}

package_body

end package_name ;

举例:

create package body product_package as

function get_products_ref_cursor return t_ref_cursor is 

v_products_ref_cursor t_ref_cursor ;

begin

open v_products_ref_cursor for 

select product_id, name, price from products ;

return v_products_ref_cursor ;

end get_products_ref_cursor ;

procedure update_product_price(

p_product_id in products.product_id%type ,

p_factor         in number

) as

v_product_count integer ;

begin 

select count(*) into v_product_count from products where product_id = p_product_id ;

if v_product_count = 1 then

update products

set price = price * p_factor

where product_id = p_product_id ;

commit ;

end if ;

exception 

when others then

rollback ;

end update_product_price ;

end product_package ;

③.调用包中的函数和过程

select product_package.get_products_ref_cursor from dual ;

call product_package.update_product_price(3 , 1.25) ;

10.触发器

触发器是当特定的SQL DML语句(insert、update或delete语句)针对特定的数据库表运行时,有数据库自动运行(或启动)的过程。
触发器可以在DML语句运行之前和之后被启动。同时,由于DML语句可能同时作用于多行,因此触发器的过程代码可能为作用的每一行运行一次(这样的触发器称为行级触发器),也可能只为所有的行运行一次(称为语句级触发器)

①.创建触发器

create [or replace] trigger trigger_name
{before | after | instead of | for} trigger_event
on table_name
[for each row]
[{forward | reverse} crossedition]
[{follows | precedes} schema.other_trigger}
[{enable | disable}]
[when trigger_condition]]
begin 

trigger_body

end trigger_name ;

其中:

or replace 表示如果该触发器已经存在,就替换现有的触发器
trigger_name 指定触发器的名称
before指定触发器在触发事件之前启动。after指定触发器在触发事件运行之后启动。instead of指定用启动触发器代替触发事件的运行。for是oracle 11g新增的,它允许创建触发器体最多由4部分组成的符合触发器
trigger_event指定启动触发器的时间
table_name指定触发器引用的表
for each row指定触发器是行级触发器,即当触发器被启动时,trigger_body中包含的代码会为每一行运行一次。如果忽略for each row,那么触发器是语句级触发器,即不管作用的行有多少,当触发器被启动时,trigger_body中包含的代码只运行一次
trigger_condition指定限制触发器实际运行的布尔条件
trigger_body中包含触发器的代码
举例:

create trigger before_product_price_update

before update of price

on products

for each row when (new.price < old.price * 0.75)

begin

dbms_output.put_line('product_id = ' || :old.product_id);

dbms_output.put_line('old price = ' || :old.price);

dbms_output.put_line('new price = ' || :new.price);

dbms_output.put_line('the price reduction is more than 25%');

insert into product_price_audit(

product_id, old_price, new_price)

values (

:old.product_id, :old.price, :new.price);

end before_product_price_update ;

②.禁用和启用触发器

alter trigger before_product_price_update disable ;

alter trigger before_product_price_update enable ;

③.删除触发器

drop trigger before_product_price_update ;





































































































































内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐