PLSQL是Oracle内部的一种编程语言。
PLSQL是一门语言。叫作过程化SQL语言(Procedural Language SQL)
PLSQL是一种过程化语言,属于第三代语言,它与C、C++、Java等语言同样关注于处理细节,能够用来实现比较复杂的业务逻辑。
PL/SQL是对结构化查询语言(SQL)的过程语言扩展。java
PL/SQL的基本单位叫作一个区段,由三个部分组成:一个声明部分,一个可运行部分,和排除-构建部分。
PL/SQL区段只被编译一次而且以可运行的形式储存,以下降响应时间。web
实际工做中,PLSQL多用于写触发器、存储过程、函数等。sql
PL/SQL的基本单位叫作一个区段,由三个部分组成:一个声明部分,一个可运行部分,和排除-构建部分。
这里声明只有运行部分是必须的,其他均是可选,以下:数据库
declare --(可选,声明变量用)
begin --(must) null;
exception --(可选)
end; --(must)
以下咱们建立一个最简单的PLSQL语句块编程
begin null;
end;
/
在命令行执行,结果以下:
数组
须要指出的是,这里的 null 不能够省略,PLSQL语句块中必须包含一条语句。bash
下面咱们写一个最简单而且打印Hello World的PLSQL。编程语言
set serveroutput on; --用于打开控制台输出服务,默认是off,则不打印
begin dbms_output.put_line('HelloWorld'); --相似于java的System.out.print
end;
/
在命令行执行,结果:
svg
declare用于声明变量。
变量名称与变量类型不可省略,默认值经过 :=
赋值,默认值能够省略。
格式以下:函数
declare
v_variable1 variable_type [ := default_value];
v_variable2 variable_type [ := default_value];
变量声明
规则:
v_
开头;PLSQL的基本变量类型有7个。以下:
根据以上类型,咱们写一个含有变量声明的PLSQL。
declare
v_temp number(1);
v_count binary_integer := 0;
v_sal number(7,2) :=4000.00;
v_date date := sysdate;
v_pi constant number(3,2) := 3.14; --相似于Java的final关键字,表示常量
v_valid boolean := false;
v_name varchar2(20) not null := 'MyName';
begin
dbms_output.put_line('v_temp value: '||v_temp);
dbms_output.put_line('v_count value: '||v_count);
dbms_output.put_line('v_sal value: '||v_sal);
dbms_output.put_line('v_date value: '||v_date);
dbms_output.put_line('v_pi value: '||v_pi);
-- dbms_output.put_line('v_valid value: '||v_valid); --不能打印boolean值
dbms_output.put_line('v_name value: '||v_name);
end;
命令行结果以下:
这里须要指出的是,PLSQL的dbms_output.put_line()
函数不能直接打印boolean类型。
在工做中,变量的做用更多的是存储某个字段中的值,于是保证变量数据类型与字段数据类型一致是颇有必要的。
PLSQL中,在变量声明时,能够经过%type
得到指定字段(变量)的数据类型。这种方式能够确保当源表的字段类型改变时,变量的类型自动改变。
以下:
declare
v_empno number(4);
v_empno2 emp.empno%type; --v_empno2的类型是表emp的empno字段的类型
v_empno3 v_empno2%type; --v_empno3的类型是变量v_empno2的类型
PLSQL提供了两种复合变量。
以下声明一个Table变量
declare
type type_table_emp_empno is table of emp.empno%type index by binary_integer; --声明一个数组类型
v_empnos type_table_emp_empno; --利用类型声明变量
begin
v_empno(0) := 7369;
v_empno(2) := 7839;
v_empno(-1) := 9999; --Table类型的下标能够是负数
dbms_output.put_line(v_empno(-1));
end;
声明一个Record类型
--RECORD类型
declare
type type_record_dept is record
(
deptno dept.deptno%type,
dname dept.dname%type,
loc dept.loc%type
);
v_temp type_record_dept;
begin
v_temp.deptno := 50;
v_temp.dname := 'aaa';
v_temp.loc := 'bj';
dbms_output.put_line(v_temp.deptno||v_temp.dname||v_temp.loc);
end;
这里若是表的结构发生了变化,咱们如何保证声明的复合变量和表中的变量相同呢,能够经过rowtype实现。
%rowtype:定义一个表示表中一行记录的变量
以下:
declare
v_temp dept%rowtype;
begin
v_temp.deptno := 50;
v_temp.dname := 'aaa';
v_temp.loc := 'bj';
dbms_output.put_line(v_temp.deptno||v_temp.dname||v_temp.loc); end;
这里关于 %type
和 %rowtype
作一个简单的对比说明:
以下:
%TYPE
为了使一个变量的数据类型与另外一个已经定义了的变量(尤为是表的某一列)的数据类型相一致,当被参照的那个变量的数据类型改变了以后,这个新定义的变量的数据类型会自动跟随其改变,无需修改PL/SQL程序。当不能确切地知道被参照的那个变量的数据类型时,就只能采用这种方法定义变量的数据类型。
%ROWTYPE
若是一个表有较多的列,使用%ROWTYPE来定义一个表示表中一行记录的变量,比分别使用%TYPE来定义表示表中各个列的变量要简洁得多,而且不容易遗漏、出错。这样会增长程序的可维护性。当表的某些列的数据类型改变了以后,这个新定义的变量的数据类型会自动跟随其改变,无需修改PL/SQL程序。当不能确切地知道被参照的那个表的结构及其数据类型时,就只能采用这种方法定义变量的数据类型。
异常块经过exception关键字声明,以下:
declare
v_num number := 0;
begin
v_num := 2/v_num;
dbms_output.put_line(v_num);
exception
when others then
dbms_output.put_line('error');
end;
/
PLSQL中能够写SQL语句,和平时的SQL语法基本一致,须要注意的是如下几点:
这里须要解释的是,select语句不返回值则无心义,返回许多则变量装不了。
下面咱们有一张测试表,而且根据这张表,实验理解PLSQL的SQL语句。
set serveroutput on; --该服务开启一次便可,若是以前开启过无需再次开启。
declare
v_dep ljb_test.dep%type; --type
v_name ljb_test.name%type; --type
v_test ljb_test%rowtype; --rowtype
--测试insert&update的数据
v_new_dep ljb_test.dep%type := 10;
v_new_name ljb_test.name%type := '小明';
v_new_salary ljb_test.salary%type := 5000;
v_anoter_name ljb_test.name%type := '大明';
begin --select语句必须返回一条记录,而且只能返回一条记录 select dep, name into v_dep, v_name from ljb_test where salary = 6000; --限定条件必定要保证返回一条记录
dbms_output.put_line(v_dep||v_name);
select * into v_test from ljb_test where salary = 6000; --限定条件必定要保证返回一条记录
dbms_output.put_line(v_test.dep||v_test.name||v_test.salary);
--insert,与普通SQL语句一致,只是能够插入变量
insert into ljb_test values(v_new_dep, v_new_name, v_new_salary);
commit; --执行完插入语句记得提交事务
--update,与普通SQL语句一致,只是能够插入变量
update ljb_test t set name = v_anoter_name where t.name = v_new_name;
--delete,与普通SQL语句一致,只是能够插入变量
delete from ljb_test t where t.dep = '1'; --删除部门1的记录
end;
/
输出结果:
同时咱们看下更新后的测试表:
能够看到数据已经更新。
DDL语句不能直接执行,必须使用 execute immediate ''
进行包裹;
以下,咱们经过PLSQL建立一张表:
begin execute immediate 'create table tb(aaa varchar2(255) default ''asd'')'; --两个单引号表明一个单引号
end;
/
须要指出的两点:
execute immediate ''
包裹,不然报错ORA-06550;咱们在命令行执行,并查看该表
一样的,truncate和drop写法以下:
begin execute immediate 'truncate table tb'; --删除记录,释放表空间
execute immediate 'drop table tb'; --删除记录及定义,释放表空间 end; /
可是有个例外:就是delete。
delete既可使用execute也能够不使用,以下两种写法均是正确的。
begin execute immediate'delete tb'; --delete删除记录,但不释放表空间
commit;
delete tb;
commit;
end;
/
这里能够这样理解,实际上delete table_name
等价于 delete from table_name
,是一种DML语言,于是能够直接执行。
这里针对drop、truncate、delete在复习下三者的区别
判断循环语句是PLSQL的重要语句。
判断语句也叫作分支语句,经过if实现。以下经过一个简单实例进行理解:
对于以下表:
咱们写一个薪水等级判断语句:
<3000 low
3000~5000 middle
其他 high
--if语句
declare
v_sal ljb_test.salary%type;
begin
select salary into v_sal from ljb_test where name = 'ri';
if(v_sal < 3000) then
dbms_output.put_line('low');
elsif(v_sal < 5000) then --elsif
dbms_output.put_line('middle');
else --else后面没有then
dbms_output.put_line('high');
end if;
end;
/
set serveroutput on; --也能够放在下面,可是须要在以前增长一个 /
/
和Java等语句的if语句极其类似,不一样的是具体的语法,须要注意其特色。
输出结果以下:
与Java中的循环语句相似,PLSQL也要拥有相似的三种循环语句。为了方便理解,我使用Java循环的区分方式来区分PLSQL的三种循环。
即:
do while循环
while循环
for循环
对于三种循环,均具备如下特色:
PLSQL的循环必定是以loop开头,以end loop结束。
先打印,而后在判断条件,以下:
--相似于do while 循环
set serveroutput on;
declare
i binary_integer := 1; --声明一个计数变量
begin
loop --循环老是loop开头
dbms_output.put_line(i);
i := i + 1;
exit when(i>=11); --循环退出语句
end loop; --循环老是end loop结束
end;
/
命令行打印结果以下:
先判断,在循环打印
--while循环
declare
j binary_integer := 1; --声明一个计数变量
begin
while j<11 loop --循环退出语句,循环老是loop开头
dbms_output.put_line(j);
j := j+1;
end loop; --循环老是end loop结束
end;
/
结果以下:
for循环无需declare块声明变量。
1..10表示1-10,注意是两个点。
--for循环
begin --for循环无需declare声明变量
for k in 1..10 loop --1..10表示1-10,注意是两个点
dbms_output.put_line(k);
end loop;
for k in reverse 1..10 loop --reverse表示逆序
dbms_output.put_line(k);
end loop;
end;
/
结果以下:
前面说过,PLSQL是一门过程语言,因此也支持相似于Java的异常处理机制。
须要指出的是,PLSQL的异常处理实际工做中并不经常使用,缘由很简单,为了提升程序的可移植性(用于多个数据库),咱们通常把异常处理放在Java等语言中处理。
异常处理的核心应用通常是日志表。
因此,下文咱们仅做简单的介绍。
首先,明确一点,异常处理只能捕获运行时的异常,编译时的异常没法捕获,于是若是存在编译异常,则程序没法运行,更没法调用异常处理机制。
begin insert into dual values('',''); --插入字段数明显不符合
exception
when others then
dbms_output.put_line('ERROR!');
end;
/
这时,程序没法编译经过,会直接报错:
下面,咱们就以前PLSQL中select语句返回一条记录的要求,来写几个简单的异常捕获程序:
set serveroutput on;
declare
v_name ljb_test.name%type;
begin
select name into v_name from ljb_test;
exception
when too_many_rows then --too_many_rows,返回值超过一条
dbms_output.put_line('返回值太多');
when others then
dbms_output.put_line('error');
end;
/
运行程序,结果以下:
declare
v_name ljb_test.name%type;
begin
select name into v_name from ljb_test where 1 = 0;
exception
when no_data_found then --no_data_found,无数据异常
dbms_output.put_line('无数据');
when others then
dbms_output.put_line('error');
end;
/
结果以下:
异常处理最核心的应用应该就是日志表,而日志表多用于存储过程等。
create table err_log( err_id number primary key, err_code number, err_msg varchar2(1024), err_date date );
create sequence seq_err_log start with 1 increment by 1;
declare
v_errcode number;
v_errmsg varchar2(1024);
v_name ljb_test.name%type;
begin --insert into dual values('0','2'); --编译时错误是没法经过异常捕获处理的
select name into v_name from ljb_test;
--commit;
exception
when others then
rollback; --回滚,取消错误操做的影响
v_errcode := SQLCODE; --SQLCODE,关键字,表明出错代码,Oracle的错误代码所有是负数
v_errmsg := SQLERRM; --SQLERRM,关键字,表明出错信息
insert into err_log values(seq_err_log.nextval,v_errcode,v_errmsg,sysdate);
commit; --不要忘记commit
end;
/
咱们查询下对应的日志表内容:
若是是存储过程当中的日志表,能够添加一个pro_name字段。
插入的时候,直接插入该存储过程的名字便可。
至此,PLSQL的基本语法已经学习完成,有关存储过程、游标等的介绍,将会另起一文,本文仅对基本语法等作简单学习总结。