存储过程、函数、包、触发器、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 ;
相关文章推荐
- 解密SQLServer2000加密存储过程,函数,触发器,视图
- 存储过程,函数及触发器
- MySQL 系列(三)你不知道的 视图、触发器、存储过程、函数、事务、索引、语句
- plsql 存储过程,函数,触发器学习
- 触发器、存储过程、函数 基本操作(三)
- Sql Server-视图 存储过程 函数 触发器 索引
- 破解字节不受限制,适用于SQLSERVER2000存储过程,函数,视图,触发器
- mysql数据库的触发器,索引,事物,函数,存储过程
- 数据库存储过程,触发器,游标,函数
- Oracle 中的PL/SQL基础、存储过程、触发器、函数、包(学习笔记)
- [MySQL] 存储过程、函数、触发器和视图的权限检查
- mysql触发器,存储过程,函数
- Oracle 查看 表 存储过程 触发器 函数 等对象定义语句的方法
- SQL Server ->> 重新创建Assembly和自动重建相关的数据库编程对象(存储过程,函数和触发器)
- 查看表被那些存储过程、函数、视图、触发器使用
- 存储过程,函数,触发器的区别
- mysql 触发器采坑记录(mysql 触发器采坑记录 由于不了解mysql创建触发器要记录创建者IP,导致更改创建者IP后,触发器不可执行。 当创建触发器(视图、存储过程、函数)时,如果没有)
- MySQL主从环境下存储过程,函数,触发器,事件的复制情况
- oracle中的游标,例外,存储过程,存储函数和触发器
- C# 得到sqlserver 数据库存储过程,触发器,视图,函数 的定义