PL/SQL程序由三个块组成,即声明部分、执行部分、异常处理部分
结构如下:
declare
/*声明部分,在此声明变量,类型及游标*/
begin
/*执行部分,过程及sql语句,程序主要部分*/
exception
/*执行异常部分,错误处理*/
end;
变量赋值
variable :=expression
字符连接
<字符串>||<字符串>
注意:空值加数字仍是空值
可转换类型赋值
char转number
v_total :=to_number('100.0')+sal;
number转char
v_comm :=to_char('123.45')||'元';
字符转日期
v_date :=to_date('2001.07.03','yyyy.mm.dd');
日期转字符
v_to_day :=to_char(sysdate,'yyyy.mm.dd hh24:mi:ss');
使用%type 定义表字段相同类型的变量
变量名 表名.字段名%type;
v_va11 emp.column1%type
使用%rowtype定义表行相同类型的变量
变量名 表名%rowtype;
v_row emp%rowtype;
ORACLE定义符合型的类型
delcare
--声明一个记录类型
type emp_record is record(
v_val1 emp.column1%type;
v_val3 emp.column2%type;
v_val3 emp.column3%type;
);
--定义一个记录类型的成员变量、
v_emp_record emp_record;
begin
select column1,column2,columb3 into v_emp_record from emp where emp_id = 100;
end;
方式一
if...then...elsif...than...else...end if;
-----------------1
if<布尔>then
--logic
end if;
-----------------2
if<布尔>then
--logic
else
--logic
end if;
-----------------3
方式二
case... when... then... end;
循环结构
方式一
loop...exit...when...end loop;
方式二
while...loop...end...loop;
方式三
for i in ...loop...end loop;
定义游标
打开游标
提取游标数据
关闭游标
declare
--1.定义游标
cursor my_cursor is select * from test;
v_row test%rowtype;
begin
--2.打开游标
open my_cursor;
--3.提取游标
fetch my_cursor into v_row;
--4.对游标进行循环操作,判断是否有下一条记录
while my_cursor%found loop
dbms_output.put_line('name:'||v_row.name);
fetch my_cursor into v_row;
end loop;
--关闭游标
close my_cursor;
end;
游标属性
%FOUND 布尔型属性 当前最近一次读记录成功返回,则为true
%NOTFOUND 布尔型属性 相反
%ISOPEN 布尔型属性 当游标已打开时返回true
%ROWCOUNT 数字型属性 返回已从游标中读取的记录数
游标for循环,自动执行游标循环功能,自动打开游标,并提取第一行游标数据...
DECLARE
CURSOR c_dl IS SELECT * FROM test;
c_row c_dl%ROWTYPE;
BEGIN
FOR c_row IN c_dl LOOP
dbms_output.put_line ( 'SQL=' || c_row.name );
END LOOP;
END;
带参数游标
DECLARE
CURSOR c_dl( x_id number) IS SELECT * FROM test where id= x_id;
c_row c_dl%ROWTYPE;
BEGIN
FOR c_row IN c_dl( x_id =>4000 ) LOOP
dbms_output.put_line ( 'SQL=' || c_row.name );
END LOOP;
END;
异常情况处理使用于处理正常执行过程中未预料的事件,程序块的异常处理
exception
when first_exception then
when second_exception then
when third_exception then
end;
--异常处理注意次序排列,但others 必须放在最后
DECLARE
CURSOR c_dl IS SELECT * FROM norm;
c_row c_dl%ROWTYPE;
BEGIN
FOR c_row IN c_dl LOOP
BEGIN
dbms_output.put_line ( 'SQL=' || c_row.name );
--当出现异常时,将异常插入日志表,并继续下一次循环
EXCEPTION
WHEN OTHERS THEN
BEGIN
dbms_output.put_line ( 'eerrrrr');
END;
END;
END LOOP;
END;
1.预定义错误 -大约有24个,无需在程序定义,由oracle自动
2.非预定义错误
DECLARE
--1.定义异常
temp_exception exception;
--2.将定义好的异常情况,与标准oracle错误联系起来
PRAGMA EXCEPTION_INIT(temp_exception,-2292);
BEGIN
delete from test where id=2;
exception
--3.处理异常
when temp_exception then dbms_output.put_line ( '违反完整性约束' );
END;
3.用户定义错误
DECLARE
e_too_high_excep exception;
v_val test.ID%type;
BEGIN
select id into v_val from test where id=2;
if v_val>1 then
raise e_too_high_excep;
end if;
exception
when e_too_high_excep then dbms_output.put_line ( 'to high' );
END;
存储函数和过程
过程和函数的唯一区别是函数总向调用者返回数据,而过程则不返回数据
--创建存储过程调用
--输入参数 IN OR OUT
CREATE OR REPLACE PROCEDURE BAK_TEST(table_name in varchar)
return number
AS
BEGIN
END;
--需要单独选中执行存储过程调用(下面只是调用存储过程语法)
--参数为 需要备份的表名
BEGIN
BAK_TEST('norm');
END;
利用存储函数备份表案例
--创建存储过程调用
CREATE OR REPLACE PROCEDURE BAK_TEST(table_name in varchar)
AS
s_table_name VARCHAR(100);
s_date VARCHAR(20);
str_sql VARCHAR2(500);
BEGIN
for cryptic_rec in (
SELECT * FROM norm
)
loop
BEGIN
select to_char(sysdate,'yyyymmdd') INTO s_date from dual;
s_table_name := cryptic_rec.name || '_' ||s_date;
dbms_output.put_line ( '-- s_table_name=' || s_table_name );
str_sql :='CREATE TABLE '|| s_table_name || ' AS SELECT * FROM '|| cryptic_rec.name;
EXECUTE IMMEDIATE str_sql;
dbms_output.put_line ( '--SQL=' || str_sql );
--当出现异常时,将异常插入日志表,并继续下一次循环
EXCEPTION
WHEN OTHERS THEN
BEGIN
dbms_output.put_line ( 'error-SQL=' || str_sql );
END;
END;
end loop;
END;
--需要单独选中执行存储过程调用(下面只是调用存储过程语法)
--参数为 需要备份的表名
BEGIN
BAK_TEST('norm');
END;
create [or replace] trigger trigger_name
{before|after}
{insert|delete|update [of column]}
on [schema.]table_name
[for each row]
[when condition]
trigger_body;
--分为行触发和语句触发
案例
create or replace trigger hell_trigger
after
update on employees
--for each row
begin
dbms_output.put_line('hello');
end;
-- old,new
create or replace trigger del_trigger
after
delete on employees
for each row
begin
insert into my_emp_bak
values(:old.emp_id,:old.salary);
end;
Oracle 大小写转换函数
转大写UPPER
转小写LOWER
测试:
select UPPER('Test') as u from dual;--TEST
select LOWER('Test') as l from dual;--test
注意:
1.sys用数据库的超级用户,数据库内很多重要的东西(数据字典表、内置包、静态数据字典视图等)都属于这个用户,sys用户必须以sysdba身份登录。
2.提示 ORA-01031: 权限不足
执行DDL报错
在oracle存储过程中,默认是可以直接执行DML和DQL的,但是执行CREATE这种的DDL则需要借助EXECUTE IMMEDIATE ···了,如下备份表语句
--抄表表备份
SELECT TO_CHAR(SYSDATE,'YYMMDD') INTO V_DQRQ FROM DUAL;
V_CREATESQL := 'CREATE TABLE SF_EBZCB'||V_DQRQ||'_T AS SELECT * FROM SF_EBZCB_T';
EXECUTE IMMEDIATE V_CREATESQL;
当执行该语句时,提示 ORA-01031: 权限不足。该用户已赋予DBA权限。
原因:CREATE TABLE想使用CREATE ANY TABLE权限,而CREATE ANY TABLE权限来自DBA角色,默认情况下,虽然在会话环境中可见,但在存储过程中不可见(无效)。
即:ORACLE默认为定义者权限,定义者权限在存储过程中ROLE无效,需要显式授权。
GRANT CREATE ANY TABLE TO charge_liny;
执行上面sql显式授权后,在该用户下通过 EXECUTE IMMEDIATE 执行CREATE语句即可成功创建表。
授权其他DML权限
GRANT INSERT ANY TABLE TO CHARGE_LINY;
GRANT UPDATE ANY TABLE TO CHARGE_LINY;
GRANT DELETE ANY TABLE TO CHARGE_LINY;