2014-04-13
1.pl/sql分匿名块和命名块
匿名块语法:
DECLARE
declaration statements
BEGIN
executable statments
EXCEPTION
exception-handing statments ---异常处理
END;
命名块:存储过程,函数,触发器,包等。
2.pl/sql语句块分三部分:
1)声明部分:
2)可执行部分:
3)异常处理部分:
其中可执行部分是语句块中唯一要求必须存在的部分,声明部分和异常处理部分是可选的。
3.声明变量
1)语法:
identifier [CONSTANT] datatype [NOT NULL] [:=value |DEFAULT expr];
2)示例一
declare
v_first_name varchar2(50);
c_count constant number :=0; ----常量
v_hiredate date;
v_vaild BOLLEAN NOT NULL DEFAULT TRUE;
//显示雇员的姓名,工资,个人所得税
set serveroutput on;
declare
v_ename varchar2(20);
v_sal number(6,2);
v_tax_rate constant number(3,2) :=0.06; ---税率
v_tax_sal number(6,2);
begin
select ename,sal into v_ename,v_sal from emp where empno = &no;
v_tax_sal := v_sal * v_tax_rate; ---赋值
dbms_output.put_line('v_ename: ' || v_ename);
dbms_output.put_line('v_sal: ' || v_sal);
dbms_output.put_line('v_tax_sal: ' || v_tax_sal);
end;
3)示例二(和一声明变量方法不一样)
declare
v_ename emp.ename%type;
v_sal emp.sal%type;
v_tax_rate constant number(3,2) :=0.06; ---税率
v_tax_sal number(6,2);
begin
select ename,sal into v_ename,v_sal from emp where empno = &no;
v_tax_sal := v_sal * v_tax_rate; ---赋值
dbms_output.put_line('v_ename: ' || v_ename);
dbms_output.put_line('v_sal: ' || v_sal);
dbms_output.put_line('v_tax_sal: ' || v_tax_sal);
end;
4.标识符的命名规则
1)定义变量,建议用v_,如v_ename
2)定义常量,建议用c_,如c_tax_rate
3)定义游标,建议使用_cursor作为后缀,如emp_cursor
4)定义表类型,建议使用_table_type作为后缀,如sal_table_type
5)定义表变量,建议使用_table作为后缀,如sal_table
5.PL/SQL编译过程步骤
编译过程包括语法检查,绑定以及伪代码生成。语法检查涉及检查PL/SQL代码中的编译错误。在纠正语法错误之后,会给每个变量分配内存地址,以保存ORACLE数据,这个过程称为绑定。接下来,会产生PL/SQL语句块的伪代码,伪代码是PL/SQL引擎的指令列表,对于命名语句块,伪代码会存储在数据库中,并在程序下一次执行时使用。
6.替代变量
在匿名PL/SQL块中接受输入参数使用&或者&&作为替代变量
7.初始化变量用select into 语法
//求emp表中的平均工资
set serveroutput on;
declare
v_sal number(6,2);
begin
select avg(sal) into v_sal from emp;
dbms_output.put_line('v_sal: ' || v_sal);
end;
##在sqlplus中执行最后要加/。
8.if 语句
1)if 语法:
IF condition THEN
statements;
[ELSIF condition THEN
statements;]
[ELSE
statements;
]
END IF;
2)示例:
//如果工资小于2000,把雇员的薪水加50
set serveroutput on;
DECLARE
v_sal emp.sal%TYPE;
BEGIN
SELECT sal into v_sal FROM emp where lower(ename)=lower('&name');
if v_sal<2000 then
update emp set sal=sal+50 where lower(ename)=lower('&name');
end if;
dbms_output.put_line('v_sal: ' || v_sal);
END;
##验证
SELECT * from emp where sal<2000;
//如果job=PRESIDENT,sal=sal+200;job=MANAGER ,sal=sal+1000;other ,sal=sal+100
&empno
set serveroutput on;
DECLARE
v_sal EMP.SAL%type;
v_job EMP.JOB%type;
v_empno EMP.EMPNO%TYPE;
BEGIN
SELECT job,sal,empno into v_job,v_sal,v_empno FROM emp where empno=&no;
if v_job='PRESIDENT' then
update emp set sal=sal+200 where empno=v_empno;
elsif v_job='MANAGER' then
update emp set sal=sal+1000 where empno=v_empno;
else
update emp set sal=sal+100 where empno=v_empno;
end if;
DBMS_OUTPUT.PUT_LINE('v_job: '|| v_job);
DBMS_OUTPUT.PUT_LINE('v_sal:' || v_sal);
COMMIT;
END;
ROLLBACK; --回滚
##验证
SELECT * from emp where empno=7566;
9.循环语句
1)loop循环
loop
statements;
exit [when condition];
end loop;
//示例
create table tmp01 (id int);
declare i int :=1;
begin
loop
insert into tmp01 values(i);
commit;
exit when i>100;
i :=i+1;
end loop;
end;
select * from tmp01;
2)while 循环
while condition loop
statement1;
statement2;
..........
end loop;
//示例
create table tmp01 (id int);
declare i int :=1;
begin
while i<=100 loop
insert into tmp01 values(i);
i :=i+1;
end loop;
commit; ----批量提交
end;
select * from tmp01;
3)for 循环
for counter in [reverse] lower_bound .. upper_bound loop
statement1;
statement2;
........
end loop;
##counter变量不需要定义
//示例
drop table tmp01 purge;
create table tmp01 (id int);
begin
for i in 1..100 loop
insert into tmp01 values(i);
end loop;
commit;
end;
select * from tmp01;
4)case
//用替代变量输入部门号,使用case语句判断条件更新雇员工资
部门号为10,雇员加薪10%
部门号为20,雇员加薪8%
部门号为30,雇员加薪15%
如果输入其他数字,则显示“该部门不存在”
set serveroutput on;
DECLARE
v_deptno emp.deptno%type;
begin
v_deptno :=&deptno;
case
when v_deptno=10 then
update emp set sal=sal*1.1 where deptno=v_deptno;
when v_deptno=20 then
update emp set sal=sal*1.08 where deptno=v_deptno;
when v_deptno=30 then
update emp set sal=sal*1.15 where deptno=v_deptno;
else
dbms_output.put_line('no such department');
end case;
end;
10.SQL游标
当执行select,insert,update,delete 时oracle会为SQL语句分配相应的上下文区(context area).oracle使用上下区解析并执行相应的SQL语句,而游标就是指向上下文区的指针。
游标包括隐式游标和显示游标。其中隐式游标也称为SQL游标,专门用于处理select into,insert,update,delete语句。显示游标用于处理多行select语句。
SQL游标属性:sql%found,sql%notfound,sql%rowcount,sql%isopen等
1)sql%isopen:用于确定SQL游标是否打开。
2)sql%found/sql%notfound:用于确定SQL语句是否执行成功。
set serveroutput on;
declare
v_deptno emp.deptno%type := &no;
begin
update emp set sal = sal*1.05 where deptno=v_deptno;
if sql%notfound then
dbms_output.put_line('deptno is not exist.');
else
dbms_output.put_line('sql execute successful.');
end if;
end;
3)sql%rowcount:用于返回sql语句所作用的总计行数。
set serveroutput on;
declare
v_deptno emp.deptno%type := &no;
begin
update emp set sal = nvl(sal,0)*1.05 where deptno=v_deptno;
dbms_output.put_line('have '|| sql%rowcount || ' row changed.');
if sql%notfound then
dbms_output.put_line('deptno is not exist.');
else
dbms_output.put_line('sql execute successful.');
end if;
end;
4)案例
用替代变量输入客户名(不区分大小写)和所在城市,并修改客户所在城市,如果客户不在,则显示“该客户不在”
##创建表
create table customer(customer_id number not null,customer_name varchar2(50),
city_name varchar2(50),constraint pk_customer primary key(customer_id));
##插入数据
insert into customer values(1,'yangry','henan');
insert into customer values(2,'lisn','shangqiu');
insert into customer values(3,'lij','nanyang');
insert into customer values(4,'guoyf','luoyang');
set serveroutput on;
declare
v_uname CUSTOMER.CUSTOMER_NAME%TYPE;
v_cname CUSTOMER.CITY_NAME%TYPE;
begin
v_uname :='&uname';
v_cname :='&cname';
update customer set city_name=v_cname where upper(customer_name)=upper(v_uname);
if sql%notfound then
dbms_output.put_line('the customer is not exist');
end if;
commit;
end;
//另一种声明变量的方法
v_uname CUSTOMER.CUSTOMER_NAME%TYPE :='&uname';
v_cname CUSTOMER.CITY_NAME%TYPE :='&cname';
//begin后也可修改为:
select customer_name into v_uname from customer where upper(customer_name) = '&uname';
v_cname :='&cname';--此句不能用select的原因跟下面的set语句有关。