Oracle速查语法:PL/SQL

目录

  • 基本结构
  • 游标
  • PL/SQL表
  • PL/SQL 记录类型
  • REF 游标
  • 过程
  • 函数
  • 数据包
  • 触发器
  • 自定义对象
  • 其他

.

PL/SQL 结构

DECLARE        --声明部分
        声明语句
BEGIN         --执行部分
        执行语句

EXCEPTION         --异常处理部分
        执行语句

END;

变量声明

<变量名> 类型[:=初始值];
特殊类型 字段%type
示例: name emp.ename%type –表示name的类型和emp.ename的类型相同
表 %rowtype
示例:
test emp%rowtype –表示test的类型为emp表的行类型;也有 .empno; .ename; .sal ;等属性


常量声明

<变量名> CONSTANT 类型:=初始值; 示例: pi constant number(5,3):=3.14;


全局变量声明
VARIABLE <变量名> 类型;
示例: VARIABLE num number;


使用全局变量
:<变量名>
示例:
:num:=100;
i=:num;


查看全局变量的值
print <变量名>
示例: print num;


赋值运算符: :=
示例: num := 100;


使用SELECT <列名> INTO <变量名> FROM <表名> WHERE <条件>
注意select into 语句的返回结果只能为一行;
示例:test emp%rowtype;
select * into test from emp where empno=7788;


用户交互输入
<变量>:=’&变量’
示例:
num:=#


注意oracle的用户交互输入是先接受用户输入的所有值后在执行语句;
所以不能使用循环进行用户交互输入;

条件控制语句
IF <条件1> THEN
    语句
[ELSIF <条件2> THEN
   语句
          .
          .
          .
ELSIF <条件n> THEN
   语句]
[ELSE 
    语句]
END IF;

循环控制语句

1.LOOP

LOOP
   语句;
   EXIT WHEN <条件>
END LOOP;

2.WHILE LOOP

WHILE <条件>
LOOP
   语句;
END LOOP;

3.FOR

FOR <循环变量> IN 下限..上限
LOOP
   语句;
END LOOP;
NULL 语句
null;
表示没有操作;

注释使用
单行注释: –
多行注释:/* …….
……………*/

异常处理

EXCEPTION 
   WHEN <异常类型> THEN
            语句;
   WHEN OTHERS THEN
            语句;
END;

.

显示游标

定义:

CURSOR <游标名> IS <SELECT 语句> [FOR UPDATE | FOR UPDATE OF 字段];

[FOR UPDATE | FOR UPDATE OF 字段] –给游标加锁,既是在程序中有”UPDATE”,”INSERT”,”DELETE”语句对数据库操作时。

游标自动给指定的表或者字段加锁,防止同时有别的程序对指定的表或字段进行”UPDATE”,”INSERT”,”DELETE”操作.

在使用”DELETE”,”UPDATE”后还可以在程序中使用CURRENT OF <游标名> 子句引用当前行.

操作:

OPEN <游标名> --打开游标
    FETCH <游标名> INTO 变量1,变量2,变量3,....变量n,;
                或者
    FETCH <游标名> INTO 行对象;         --取出游标当前位置的值 
    CLOSE <游标名> --关闭游标
属性: %NOTFOUND --如果FETCH语句失败,则该属性为"TRUE",否则为"FALSE";
    %FOUND --如果FETCH语句成果,则该属性为"TRUE",否则为"FALSE";
    %ROWCOUNT --返回游标当前行的行数;
    %ISOPEN --如果游标是开的则返回"TRUE",否则为"FALSE";

使用:

LOOP循环
   示例:
DECLARE 
     cursor c_1 is select * from emp;     --定义游标
     r c_1%rowtype;      --定义一个行对象,用于获得游标的值
BEGIN
     if c_1%isopen then
          CLOSE c_1;
     end if;               
     OPEN c_1;          --判断游标是否打开.如果开了将其关闭,然后在打开
     dbms_output.put_line('行号 姓名 薪水');
     LOOP
     FETCH c_1 INTO r;     --取值
     EXIT WHEN c_1%NOTFOUND;     --如果游标没有取到值,退出循环.
     dbms_output.put_line(c_1%rowcount||' '||r.ename||' '||r.sal);    --输出结果,需要 set serverout on 才能显示.
     END LOOP;
END;

FOR循环

示例:

DECLARE 
     cursor c_1 is select ename,sal from emp;     --定义游标     
BEGIN
     dbms_output.put_line('行号 姓名 薪水');
     FOR i IN c_1         --for循环中的循环变量i为c_1%rowtype类型;
     LOOP
     dbms_output.put_line(c_1%rowcount||' '||i.ename||' '||i.sal);    --输出结果,需要 set serverout on 才能显示.
     END LOOP;
END; 

for循环使用游标是在循环开始前自动打开游标,并且自动取值到循环结束后,自动关闭游标.

游标加锁示例:

DECLARE 
     cursor c_1 is select ename,sal from emp for update of sal;     --定义游标对emp表的sal字段加锁.     
BEGIN
     dbms_output.put_line('行号 姓名 薪水');
     FOR i IN c_1         --for循环中的循环变量i为c_1%rowtype类型;
     LOOP
     UPDATE EMP set sal=sal+100 WHERE CURRENT OF c_1; --表示对当前行的sal进行跟新.
     END LOOP;
     FOR i IN c_1        
     LOOP
     dbms_output.put_line(c_1%rowcount||' '||i.ename||' '||i.sal);    --输出结果,需要 set serverout on 才能显示.
     END LOOP;
END; 

代参数的游标

定义:

CURSOR <游标名>(参数列表) IS

DECLARE 
     cursor c_1(name emp.ename%type) is select ename,sal from emp where ename=name;     --定义游标     
BEGIN
     dbms_output.put_line('行号 姓名 薪水');
     FOR i IN c_1('&name')         --for循环中的循环变量i为c_1%rowtype类型;
     LOOP
     dbms_output.put_line(c_1%rowcount||' '||i.ename||' '||i.sal);    --输出结果,需要 set serverout on 才能显示.
     END LOOP;
END; 

隐试游标

隐试游标游标是系统自动生成的。每执行一个DML语句就会产生一个隐试游标,起名字为SQL;

隐试游标不能进行”OPEN” ,”CLOSE”,”FETCH”这些操作;

属性:

    %NOTFOUND --如果DML语句没有影响到任何一行时,则该属性为"TRUE",否则为"FALSE";
    %FOUND --如果DML语句影响到一行或一行以上时,则该属性为"TRUE",否则为"FALSE";
    %ROWCOUNT --返回游标当最后一行的行数;

个人认为隐试游标的作用是判断一个DML语句;

示例:

BEGIN
    DELETE FROM EMP WHERE empno=&a;
    IF SQL%NOTFOUND THEN
        dbms_output.put_line('empno不存在');
    END IF;
   IF SQL%ROWCOUNT>0 THEN
        dbms_output.put_line('删除成功');
    END IF;
END; 

a

PL/SQL表

pl/sql表只有两列,其中第一列为序号列为INTEGER类型,第二列为用户自定义列.

定义:

TYPE <类型名> IS TABLE OF <列的类型> [NOT NULL] INDEX BY BINARY_INTEGER;

<列的类型>可以为Oracle的数据类行以及用户自定义类型;

属性方法:

.count --返回pl/sql表的总行数
.delect --删除pl/sql表的所有内容
.delect(行数) --删除pl/sql表的指定的行
.delct(开始行,结束行) --删除pl/sql表的多行
.first --返回表的第一个INDEX;
.next(行数) --这个行数的下一条的INDEX;
.last --返回表的最后一个INDEX;

使用

示例:

DECLARE
     TYPE mytable IS TABLE OF VARCHAR2(20) index by binary_integer; --定义一个名为mytable的PL/sql表类型;
     cursor c_1 is select ename from emp; 
     n number:=1;
     tab_1 mytable; --为mytable类型实例化一个tab_1对象;
BEGIN
     for i in c_1
     loop
          tab_1(n):=i.ename; --将得到的值输入pl/sql表
          n:=n+1; 
    end loop;
     n:=1;
     tab_1.delete(&要删除的行数); --删除pl/sql表的指定行
     for i in tab_1.first..tab_1.count
     loop
          dbms_output.put_line(n||' '||tab_1(n)); --打印pl/sql表的内容
          n:=tab_1.next(n);
     end loop;
EXCEPTION 
     WHEN NO_DATA_FOUND THEN                    --由于删除了一行,会发生异常,下面语句可以接着删除的行后显示
          for i in n..tab_1.count+1
     loop
          dbms_output.put_line(n||' '||tab_1(n));
          n:=tab_1.next(n);
     end loop; 
END; 

.

PL/SQL记录

pl/sql表只有一行,但是有多列。

定义:

TYPE <类型名> IS RECORD <列名1 类型1,列名2 类型2,...列名n 类型n,> [NOT NULL]

<列的类型>可以为Oracle的数据类行以及用户自定义类型;可以是记录类型的嵌套

使用

示例:

DECLARE
     TYPE myrecord IS RECORD(id emp.empno%type,
     name emp.ename%type,sal emp.sal%type);     --定义一个名为myrecoed的PL/sql记录类型;
     rec_1 myrecord; --为myrecord类型实例化一个rec_1对象;
BEGIN
          select empno,ename,sal into rec_1.id,rec_1.name,rec_1.sal
          from emp where empno=7788;        --将得到的值输入pl/sql记录
          dbms_output.put_line(rec_1.id||' '||rec_1.name||' '||rec_1.sal); --打印pl/sql记录的内容
END; 

结合使用PL/SQL表和PL/SQL记录

示例:

DECLARE
     CURSOR c_1 is select empno,ename,job,sal from emp;
     TYPE myrecord IS RECORD(empno emp.empno%type,ename emp.ename%type,
job emp.job%type,sal emp.sal%type);     --定义一个名为myrecoed的PL/sql记录类型;
     TYPE mytable IS TABLE OF myrecord index by binary_integer; 
                                                                   --定义一个名为mytable的PL/sql表类型;字段类型为PL/sql记录类型;

     n number:=1;
     tab_1 mytable; --为mytable类型实例化一个tab_1对象;
BEGIN
          --赋值
          for i in c_1
          loop
               tab_1(n).empno:=i.empno;
               tab_1(n).ename:=i.ename;                     
               tab_1(n).job:=i.job;
               tab_1(n).sal:=i.sal;
               n:=n+1;
          end loop;
          n:=1;
          --输出
          for i in n..tab_1.count
          loop
                dbms_output.put_line(i||' '||tab_1(i).empno
                ||' '||tab_1(i).ename||' '||tab_1(i).job||' '||tab_1(i).sal);
          end loop;
END; 

.

强型REF游标

定义:TYPE <游标名> IS REF CURSOR RETURN<返回类型>;

操作:

OPEN <游标名> For <select 语句> --打开游标
    FETCH <游标名> INTO 变量1,变量2,变量3,....变量n,;
                或者
    FETCH <游标名> INTO 行对象;         --取出游标当前位置的值 
    CLOSE <游标名> --关闭游标
属性: %NOTFOUND --如果FETCH语句失败,则该属性为"TRUE",否则为"FALSE";
    %FOUND --如果FETCH语句成果,则该属性为"TRUE",否则为"FALSE";
    %ROWCOUNT --返回游标当前行的行数;
    %ISOPEN --如果游标是开的则返回"TRUE",否则为"FALSE";

使用:

示例:

DECLARE 
     type c_type is ref cursor return emp%rowtype;     --定义游标
     c_1 c_type;      --实例化这个游标类型
     r emp%rowtype;
BEGIN
     dbms_output.put_line('行号 姓名 薪水');
     open c_1 for select * from emp;
     loop 
     fetch c_1 into r;
     exit when c_1%notfound;
     dbms_output.put_line(c_1%rowcount||' '||r.ename||' '||r.sal);    --输出结果,需要 set serverout on 才能显示.
     END LOOP;
close c_1;
END;

弱型REF游标

定义:TYPE <游标名> IS REF CURSOR;

OPEN <游标名> For <select 语句> --打开游标
    FETCH <游标名> INTO 变量1,变量2,变量3,....变量n,;
                或者
    FETCH <游标名> INTO 行对象;         --取出游标当前位置的值 
    CLOSE <游标名> --关闭游标
属性: %NOTFOUND --如果FETCH语句失败,则该属性为"TRUE",否则为"FALSE";
    %FOUND --如果FETCH语句成果,则该属性为"TRUE",否则为"FALSE";
    %ROWCOUNT --返回游标当前行的行数;
    %ISOPEN --如果游标是开的则返回"TRUE",否则为"FALSE";

示例:

set autoprint on;
var c_1 refcursor;
DECLARE
   n number;
BEGIN
   n:=&请输入;
   if n=1 then
         open :c_1 for select * from emp;
   else 
         open :c_1 for select * from dept;
   end if;
END; 

.

过程

定义:CREATE [OR REPLACE] PROCEDURE <过程名>[(参数列表)] IS
[局部变量声明]
BEGIN
可执行语句
EXCEPTION
异常处理语句
END [<过程名>];


变量的类型:in 为默认类型,表示输入; out 表示只输出;in out 表示即输入又输出;


操作以有的过程:在PL/SQL块中直接使用过程名;在程序外使用execute <过程名>[(参数列表)]

使用:

示例:
创建过程:

create or replace procedure p_1(n in out number) is
    r emp%rowtype;
BEGIN
     dbms_output.put_line('姓名 薪水');
     select * into r from emp where empno=n;
     dbms_output.put_line(r.ename||' '||r.sal);    --输出结果,需要 set serverout on 才能显示.
    n:=r.sal; 
END;
使用过程:
declare
    n number;
begin
    n:=&请输入员工号;
    p_1(n);
    dbms_output.put_line('n的值为 '||n);
end; 

删除过程:
DROP PROCEDURE <过程名>;

.

函数

定义:CREATE [OR REPLACE] FUNCTION <过程名>[(参数列表)] RETURN 数据类型 IS
[局部变量声明]
BEGIN
可执行语句
EXCEPTION
异常处理语句
END [<过程名>];


变量的类型:in 为默认类型,表示输入; out 表示只输出;in out 表示即输入又输出;

使用:

示例:
创建函数:

create or replace function f_1(n number) return number is
    r emp%rowtype;
BEGIN
     dbms_output.put_line('姓名 薪水');
     select * into r from emp where empno=n;
     dbms_output.put_line(r.ename||' '||r.sal);    --输出结果,需要 set serverout on 才能显示.
     return r.sal;
END;
使用函数:
declare
    n number;
     m number;
begin
    n:=&请输入员工号;
    m:=f_1(n);
    dbms_output.put_line('m的值为 '||m);
end; 

删除函数:
DROP FUNCTION <函数名>;


.

数据包

定义: 定义包的规范
CREATE [OR REPLACE] PACKAGE <数据包名> AS
–公共类型和对象声明
–子程序说明
END;
定义包的主体
CREATE [OR REPLACE] PACKAGE BODY <数据包名> AS
–公共类型和对象声明
–子程序主体
BEGIN
-初始化语句
END;

使用:

示例:
创建数据包规范:

create or replace package pack_1 as
      n number;
      procedure p_1;
      FUNCTION f_1 RETURN number;
end;

创建数据包主体:

create or replace package body pack_1 as
  procedure p_1 is 
       r emp%rowtype;
  begin 
       select * into r from emp where empno=7788;
       dbms_output.put_line(r.empno||' '||r.ename||' '||r.sal);
   end;

   FUNCTION f_1 RETURN number is
       r emp%rowtype;
   begin
        select * into r from emp where empno=7788;
       return r.sal;
   end;
end;

使用包:

declare 
      n number;
begin
      n:=&请输入员工号;
      pack_1.n:=n;
      pack_1.p_1;
      n:=pack_1.f_1;
      dbms_output.put_line('薪水为 '||n);
end;

在包中使用REF游标
示例:
创建数据包规范:

create or replace package pack_2 as
     TYPE c_type is REF CURSOR; --建立一个ref游标类型
     PROCEDURE p_1(c1 in out c_type); --过程的参数为ref游标类型;
end;

创建数据包主体:

create or replace package body pack_2 as
  PROCEDURE p_1(c1 in out c_type) is 
  begin 
       open c1 for select * from emp;
   end;
end;

使用包:

var c_1 refcursor;
set autoprint on;
execute pack_2.p_1(:c_1);

删除包:
DROP PACKAGE <包名>;


.

触发器


创建触发器:

    CREATE [OR REPLACE] TRIGGER <触发器名>
    BEFORE|AFTER
    INSERT|DELETE|UPDATE [OF <列名>] ON <表名>
    [FOR EACH ROW]
     WHEN (<条件>)
     sql块>
 关键字"BEFORE"在操作完成前触发;"AFTER"则是在操作完成后触发;
 关键字"FOR EACH ROW"指定触发器每行触发一次.
  关键字"OF <列名>" 不写表示对整个表的所有列.
 WHEN (<条件>)表达式的值必须为"TRUE".

特殊变量:
:new –为一个引用最新的列值;
:old –为一个引用以前的列值; 这些变量只有在使用了关键字 “FOR EACH ROW”时才存在.且update语句两个都有,而insert只有:new ,delect 只有:old;


使用RAISE_APPLICATION_ERROR
语法:RAISE_APPLICATION_ERROR(错误号(-20000到-20999),消息[,{true|false}]);
抛出用户自定义错误.
如果参数为’TRUE’,则错误放在先前的堆栈上.


INSTEAD OF 触发器
INSTEAD OF 触发器主要针对视图(VIEW)将触发的dml语句替换成为触发器中的执行语句,而不执行dml语句.

禁用某个触发器
ALTER TRIGGER <触发器名> DISABLE
重新启用触发器
ALTER TRIGGER <触发器名> ENABLE
禁用所有触发器
ALTER TRIGGER <触发器名> DISABLE ALL TRIGGERS
启用所有触发器
ALTER TRIGGER <触发器名> ENABLE ALL TRIGGERS
删除触发器
DROP TRIGGER <触发器名>

.

自定义对象

创建对象:
CREATE [OR REPLACE] TYPE <对象名> AS OBJECT(
属性1 类型
属性2 类型


方法1的规范(MEMBER PROCEDURE <过程名>
方法2的规范 (MEMBER FUNCTION <函数名> RETURN 类型)
      .

PRAGMA RESTRIC_REFERENCES(<方法名>,WNDS/RNDS/WNPS/RNPS);
关键字”PRAGMA RESTRIC_REFERENCES”通知ORACLE函数按以下模式之一操作;
WNDS-不能写入数据库状态;
RNDS-不能读出数据库状态;
WNPS-不能写入包状态;
RNDS-不能读出包状态;

创建对象主体:
  CREATE [OR REPLACE] TYPE body <对象名> AS 
  方法1的规范(MEMBER PROCEDURE <过程名> is   
  方法2的规范 (MEMBER FUNCTION <函数名> RETURN 类型 is   
 END;

使用MAP方法和ORDER方法

用于对自定义类型排序。每个类型只有一个MAP或ORDER方法。
 格式:MAP MEMBER FUNCTION <函数名> RETURN 类型 
        ORDER MEMBER FUNCTION <函数名> RETURN NUMBER

创建对象表

CREATE TABLE <表名> OF <对象类型>

示例:

  1. 创建name 类型
     create or replace type name_type as object(
          f_name varchar2(20),
          l_name varchar2(20),
          map member function name_map return varchar2); 

     create or replace type body name_type as
          map member function name_map return varchar2 is --对f_name和l_name排序
          begin 
               return f_name||l_name;
          end;
          end;

2 创建address 类型

     create or replace type address_type as object
       ( city varchar2(20),
           street varchar2(20),
           zip number,
      order member function address_order(other address_type) return number);

      create or replace type body address_type as
      order member function address_order(other address_type) return number is --对zip排序
      begin
           return self.zip-other.zip;
      end;
      end;

3 创建stu对象

       create or replace type stu_type as object (
       stu_id number(5),
       stu_name name_type,
       stu_addr address_type,
       age number(3),
       birth date, 
       map member function stu_map return number,
      member procedure update_age);

      create or replace type body stu_type as
       map member function stu_map return number is --对stu_id排序
       begin
             return stu_id;
       end;
      member procedure update_age is --求年龄用现在时间-birth
       begin 
             update student set age=to_char(sysdate,'yyyy')-to_char(birth,'yyyy') where stu_id=self.stu_id;
       end; 
       end; 
  1. 创建对象表
    `create table student of stu_type(primary key(stu_id));`

5.向对象表插值

      insert into student values(1,name_type('关','羽'),address_type('武汉','成都路',43000), null,sysdate-365*20);

6.使用对象的方法

     delcare
          aa stu_type;
     begin
          select value(s) into aa from student s where stu_id=1; --value()将对象表的每一行转成行对象括号中必须为表的别名
          aa.update_age();
     end; 

7.select stu_id,s.stu_name.f_name,s.stu_name.l_name from student s; –查看类型的值

8.select ref(s) from student s ; –ref()求出行对象的OID,括号中必须为表的别名;deref()将oid变成行队像;

.

其他

1.在PL/SQL中使用DDL

 将sql语句赋给一个varchar2变量,在用execute immediate 这个varchar2变量即可;
 示例:
     declare
          str varchar2(200);
     begin 
          str:='create table test(id number,name varchar2(20))'; --创建表
          execute immediate str;   
          str:='insert into test values(3,''c'')'; --向表里插数据
          execute immediate str; 
     end;    

但是要队这个表插入数据也必须使用execute immediate 字符变量

2.判断表是否存在;
示例:

     declare
          n tab.tname%type;
     begin
          select tname into n from tab where tname='&请输入表名';
          dbms_output.put_line('此表以存在');
     exception
          when no_data_found then
          dbms_output.put_line('还没有此表');
     end; 

2.查看以有的过程;
示例:

select object_name,object_type,status from user_objects where object_type='PROCEDURE';

结束

你可能感兴趣的:(数据库基础)