热门标签 | HotTags
当前位置:  开发笔记 > 数据库 > 正文

PL/SQL块的学习(精华)

PL/SQL块declarebegin--SQL语句--直接写的SQL语句(DML/TCL)--间接写executeimmediateDDL/DCL命令字符串--select语句1必须带有into子句selectempnointoenofromempwhereempno=7369

  PL/SQL块

  declare

  begin

  --SQL语句

  --直接写的SQL语句(DML/TCL)

  --间接写execute immediate

  --select 语句

  <1>必须带有into子句

  select empno into eno from emp

  where empno =7369;

  <2>只能查到一行**********

  <3>字段个数必须和变量的个数一致

  exception

  --异常

  when <异常名字> then --特定异常

  <处理语句>

  when others then --所有异常都可捕获

  <处理语句>

  end;

  <例子>

  编写程序 向DEPT表中插入一条记录,

  从键盘输入数据,如果

  数据类型输入错误要有提示

  无法插入记录 也要有提示

  只能输入正数,如果有负数提示

  declare

  n number;

  no dept.deptno%type;

  nm dept.dname%type;

  lc dept.loc%type;

  exp exception; --异常的变量

  exp1 exception;

  num number:=0; --计数器

  pragma exception_init(exp,-1); --预定义语句

  --(-1错误和异常变量关联)

  pragma exception_init(exp1,-1476);

  e1 exception; --自定义异常变量

  begin

  --输入值

  no := '&编号';

  num := num + 1;

  if no <0 then

  raise e1; --自定义异常的引发

  end if;

  nm := '&名称';

  num := num +1;

  lc := '&地址';

  num := num +1;

  n := 10 /0;

  insert into dept values (no,nm,lc);

  num := num +1;

  commit;

  exception

  --自定义异常

  when e1 then

  dbms_output.put_line('编号不能为负数');

  --数据类型不对

  when value_error then

  if num =0 then

  dbms_output.put_line('编号数据类型不对');

  elsif num = 1 then

  dbms_output.put_line('名称数据类型不对');

  elsif num =2 then

  dbms_output.put_line('地址数据类型不对');

  end if;

  rollback;

  --主键冲突

  when exp then

  --sqlcode全局变量 异常错误号

  --sqlerrm全局变量 异常的文字信息

  --dbms_output.put_line('异常的编号:'||sqlcode);

  --dbms_output.put_line('异常的内容:'||sqlerrm);

  --dbms_output.put_line('编号已存在') ;

  rollback;

  --非预定义异常(关联错误号)

  when exp1 then

  --dbms_output.put_line('0做了除数') ;

  raise_application_error(-20001,'0做了除数'); --引起一个自定义的错误

  --预先保留-20001 到 -29999编号

  rollback;

  --其他的异常

  when others then

  dbms_output.put_line('异常的编号:'||sqlcode);

  dbms_output.put_line('异常的内容:'||sqlerrm);

  -- dbms_output.put_line('出现错误');

  rollback;

  end;

  -- insert into dept values (40,'asdf','asdf');

  <简单的做法>

  --存放异常的

  create table save_exp(

  bh number,

  wz varchar2(1000)

  );

  declare

  no dept.deptno%type;

  nm dept.dname%type;

  lc dept.loc%type;

  errno number;

  errtext varchar2(1000);

  begin

  no := '&编号';

  nm := '&名称';

  lc := '&地址';

  insert into dept values (no,nm,lc);

  commit;

  exception

  when others then

  rollback;

  errno := sqlcode;

  errtext := sqlerrm;

  insert into save_exp values (errno,errtext);

  commit;

  end;

  <游标> 内存中的一块区域,存放的是select 的结果

  1。 隐式游标

  单条sql语句所产生的结果集合

  用关键字SQL表示隐式游标

  4个属性 %rowcount 影响的记录的行数 整数

  %found 影响到了记录 true

  %notfound 没有影响到记录 true

  %isopen 是否打开 布尔值 永远是false

  多条sql语句 隐式游标SQL永远指的是最后一条sql语句的结果

  主要使用在update 和 delete语句上

  2。 显式游标

  select语句上 使用显式游标

  明确能访问结果集

  for循环游标

  参数游标

  解决多行记录的查询问题

  fetch游标

  显示游标

  需要明确定义

  (1)FOR循环游标 (常用的一种游标)

  --<1>定义游标

  --<2>定义游标变量

  --<3>使用for循环来使用这个游标

  --前向游标 只能往一个方向走

  --效率很高

  declare

  --类型定义

  cursor cc is select empno,ename,job,sal

  from emp where job = 'MANAGER';

  --定义一个游标变量

  ccrec cc%rowtype;

  begin

  --for循环

  for ccrec in cc loop

  dbms_output.put_line(ccrec.empno||'-'||ccrec.ename||'-'||ccrec.job||'-'||ccrec.sal);

  end loop;

  end;

  (2) fetch游标

  --使用的时候 必须要明确的打开和关闭

  declare

  --类型定义

  cursor cc is select empno,ename,job,sal

  from emp where job = 'MANAGER';

  --定义一个游标变量

  ccrec cc%rowtype;

  begin

  --打开游标

  open cc;

  --loop循环

  loop

  --提取一行数据到ccrec中

  fetch cc into ccrec;

  --判断是否提取到值,没取到值就退出

  --取到值cc%notfound 是false

  --取不到值cc%notfound 是true

  exit when cc%notfound;

  dbms_output.put_line(ccrec.empno||'-'||ccrec.ename||'-'||ccrec.job||'-'||ccrec.sal);

  end loop;

  --关闭

  close cc;

  end;

  游标的属性4种

  %notfound fetch是否提到数据 没有true 提到false

  %found fetch是否提到数据 有true 没提到false

  %rowcount 已经取出的记录的条数

  %isopen 布尔值 游标是否打开

  declare

  --类型定义

  cursor cc is select empno,ename,job,sal

  from emp where job = 'MANAGER';

  --定义一个游标变量

  ccrec cc%rowtype;

  begin

  --打开游标

  open cc;

  --loop循环

  loop

  --提取一行数据到ccrec中

  fetch cc into ccrec;

  --判断是否提取到值,没取到值就退出

  --取到值cc%notfound 是false

  --取不到值cc%notfound 是true

  exit when (cc%notfound or cc%rowcount =3);

  dbms_output.put_line(cc%rowcount||'-'||ccrec.empno||'-'||ccrec.ename||'-'||ccrec.job||'-'||ccrec.sal);

  end loop;

  --关闭

  close cc;

  end;

  <例子>

  declare

  cursor cc is select dept.dname,

  emp.ename,emp.sal from

  dept,emp where dept.deptno = emp.deptno;

  ccrec cc%rowtype;

  begin

  for ccrec in cc loop

  dbms_output.put_line(ccrec.dname||'-'||ccrec.ename||'-'||ccrec.sal);

  end loop;

  end;

  (3)参数游标

  按部门编号的顺序输出部门经理的名字

  declare

  --部门

  cursor c1 is select deptno from dept;

  --参数游标c2,定义参数的时候

  --只能指定类型,不能指定长度

  --参数只能出现在select语句=号的右侧

  cursor c2(no number,pjob varchar2) is select emp.* from emp

  where deptno = no and job=pjob;

  /*

  no = 10 pjob = 'MANAGER'

  select * from emp where deptno = 10 and job = 'MANAGER';

  */

  c1rec c1%rowtype;

  c2rec c2%rowtype;

  --定义变量的时候要指定长度

  v_job varchar2(20);

  begin

  --部门

  for c1rec in c1 loop

  --参数在游标中使用

  for c2rec in c2(c1rec.deptno,'MANAGER') loop

  dbms_output.put_line(c1rec.deptno||'-'||c2rec.ename);

  end loop;

  end loop;

  end;

  <综合例子>

  求购买的商品包括了顾客"Dennis"所购买商品的顾客(姓名);**************

  思路:

  Dennis (A,B)

  别的顾客 (A,B,C) (A,C) (B,C) C

  declare

  --Dennis所购买的商品

  cursor cdennis is select productid

  from purcase where customerid=(

  select customerid from

  customer where name = 'Dennis');

  --除Dennis以外的每个顾客

  cursor ccust is select customerid

  from customer where name <> 'Dennis';

  --每个顾客购买的商品

  cursor cprod(id varchar2) is

  select productid from purcase

  where customerid = id;

  j number ;

  i number;

  c1rec cdennis%rowtype;

  c2rec ccust%rowtype;

  c3rec cprod%rowtype;

  cname varchar2(10);

  begin

  --顾客循环

  for c2rec in ccust loop

  i:=0;

  j:=0;

  for c1rec in cdennis loop

  i := i + 1;

  --每个顾客买的东西

  for c3rec in cprod(c2rec.customerid) loop

  if (c3rec.productid = c1rec.productid) then

  j := j + 1;

  end if;

  end loop;

  end loop;

  if (i=j) then

  select name into cname from

  customer where customerid = c2rec.customerid;

  DBMS_output.put_line(cname);

  end if;

  end loop;

  end;

  (4)引用游标/动态游标

  select语句是动态的

  declare

  --定义一个类型(ref cursor)弱类型

  type cur is ref cursor;

  --强类型(返回的结果集有要求)

  type cur1 is ref cursor return emp%rowtype;

  --定义一个ref cursor类型的变量

  cura cur;

  --

  c1rec emp%rowtype;

  c2rec dept%rowtype;

  begin

  DBMS_output.put_line('输出员工') ;

  open cura for select * from emp;

  loop

  fetch cura into c1rec;

  exit when cura%notfound;

  DBMS_output.put_line(c1rec.ename) ;

  end loop ;

  DBMS_output.put_line('输出部门') ;

  open cura for select * from dept;

  loop

  fetch cura into c2rec;

  exit when cura%notfound;

  DBMS_output.put_line(c2rec.dname) ;

  end loop;

  close cura;

  end;

  >>>>>存储过程和函数

  没有名字的PL/SQL块(匿名)

  有名字的PL/SQL块(子程序-存储过程和函数)

  存储过程

  create or replace procedure p1

  as

  begin

  exception

  end;

  <最简单的存储过程>

  create or replace procedure p_jd

  as

  hello varchar2(20);

  begin

  select 'Hello World' into hello from dual;

  dbms_output.put_line(hello);

  end;

  执行存储过程的方法

  <1> execute p_jd; (SQL*PLUS中SQL>)

  <2> begin

  p_jd;

  end;

  带参数的存储过程

  --输入参数in

  --不写in的参数都是输入参数

  --根据部门编号查员工姓名

  create or replace procedure p_getemp(no number)

  as

  cursor c1 is select * from emp

  where deptno = no;

  c1rec c1%rowtype;

  begin

  -- no := 20; 输入参数是不能赋值的

  for c1rec in c1 loop

  dbms_output.put_line(c1rec.ename);

  end loop;

  end;

  --输出参数out

  --根据部门编号查出部门的平均工资,返回平均工资的值

  -- in 输入 (在procedure中是不能赋值的)

  -- out 输出 (在procedure中是能赋值的)

  -- 定义参数是不能指定长度的

  --定义变量是必须指定长度的

  create or replace procedure p_getavgsal(no number,avgsal out number)

  -- no 输入参数

  -- avgsal 输出参数

  as

  aa varchar2(10); --变量

  begin

  select avg(sal) into avgsal

  from emp where deptno = no;

  end;

  调用它只能使用PL/SQL块

  declare

  av number;

  begin

  p_getavgsal(10,av);

  dbms_output.put_line('平均工资:'||round(av,2));

  end;

  --一个参数同时可以输入,也可以输出

  --输入输出参数

  create or replace procedure

  p_getavgsal(n in out number)

  as

  begin

  select avg(sal) into n

  from emp where deptno = n;

  end;

  declare

  av number;

  begin

  av := 10;

  p_getavgsal(av);

  dbms_output.put_line('平均工资:'||round(av,2));

  end;

  --带多个参数的存储过程

  create or replace procedure

  p_getM(no number,pjob varchar2) as

  --参数游标c2,定义参数的时候

  --只能指定类型,不能指定长度

  --参数只能出现在select语句=号的右侧

  cursor c2(no1 number,pjob1 varchar2) is select * from emp

  where deptno = no1 and job=pjob1;

  c2rec c2%rowtype;

  --定义变量的时候要指定长度

  v_job varchar2(20);

  begin

  --参数在游标中使用

  for c2rec in c2(no,pjob) loop

  dbms_output.put_line(c2rec.deptno||'-'||c2rec.ename);

  end loop;

  end;

  调用方法:execute p_getm(10,'MANAGER'); --按位置

  -- no = 10 , pjob = 'MANAGER'

  execute p_getm(pjob => 'MANAGER',no => 10);

  --按参数的名字 来传值

  函数:

  必须要有返回值

  只能返回一个值

  --根据部门编号查出部门的平均工资,返回平均工资的值(利用函数)

  create or replace function

  f_getavgsal(no number)

  return number

  as

  avgsal number(7,2);

  begin

  select avg(sal) into avgsal

  from emp where deptno = no;

  --返回值

  return avgsal;

  end;

  --带输出参数

  --每个部门的平均工资和工资总额

  --一个函数返回2个值

  create or replace function

  f_getavgsal(no number,sumsal out number)

  return number

  as

  avgsal number(7,2);

  begin

  --平均工资

  select avg(sal) into avgsal

  from emp where deptno = no;

  --工资总额

  select sum(sal) into sumsal

  from emp where deptno = no;

  --返回值

  return avgsal;

  end;

  --调用方法

  <1>PL/SQL块调用

  declare

  aa number;

  begin

  aa := f_getavgsal(10) ;

  dbms_output.put_line(to_char(aa));

  end;

  <2> SQL语句来调用(DML)

  select f_getavgsal(10) from dual;

  select deptno,f_getavgsal(deptno) from dept;

  <3>

  create or replace function f1

  return number

  as

  update emp set comm = 1000

  where job='CLERK';

  return sql%rowcount;

  end;

  --select语句是无法调用它的,因为其中含有修改语句

  本文来自CSDN博客,转载请标明出处:http://blog.csdn.net/shenghuiping2001/archive/2009/12/30/5105949.aspx

 


推荐阅读
  • 一、Hadoop来历Hadoop的思想来源于Google在做搜索引擎的时候出现一个很大的问题就是这么多网页我如何才能以最快的速度来搜索到,由于这个问题Google发明 ... [详细]
  • 本文详细介绍了在ASP.NET中获取插入记录的ID的几种方法,包括使用SCOPE_IDENTITY()和IDENT_CURRENT()函数,以及通过ExecuteReader方法执行SQL语句获取ID的步骤。同时,还提供了使用这些方法的示例代码和注意事项。对于需要获取表中最后一个插入操作所产生的ID或马上使用刚插入的新记录ID的开发者来说,本文提供了一些有用的技巧和建议。 ... [详细]
  • ubuntu用sqoop将数据从hive导入mysql时,命令: ... [详细]
  • Postgresql备份和恢复的方法及命令行操作步骤
    本文介绍了使用Postgresql进行备份和恢复的方法及命令行操作步骤。通过使用pg_dump命令进行备份,pg_restore命令进行恢复,并设置-h localhost选项,可以完成数据的备份和恢复操作。此外,本文还提供了参考链接以获取更多详细信息。 ... [详细]
  • 仙贝旅行是日本最大的旅游服务平台之一,为广大用户提供优质的日本定制游服务。随着用户数量的增长,仙贝旅行决定与智齿科技合作,全面替换原有客服系统,打造全新的在线客服体系。该体系具备多渠道快速接入的能力,让仙贝旅行轻松与各个渠道的接入用户完成沟通。同时,机器人与人工协同发力,提升客户服务水平。 ... [详细]
  • 本文介绍了一些Java开发项目管理工具及其配置教程,包括团队协同工具worktil,版本管理工具GitLab,自动化构建工具Jenkins,项目管理工具Maven和Maven私服Nexus,以及Mybatis的安装和代码自动生成工具。提供了相关链接供读者参考。 ... [详细]
  • 本文由编程笔记#小编为大家整理,主要介绍了StartingzookeeperFAILEDTOSTART相关的知识,希望对你有一定的参考价值。下载路径:https://ar ... [详细]
  • 本文介绍了在Linux下安装和配置Kafka的方法,包括安装JDK、下载和解压Kafka、配置Kafka的参数,以及配置Kafka的日志目录、服务器IP和日志存放路径等。同时还提供了单机配置部署的方法和zookeeper地址和端口的配置。通过实操成功的案例,帮助读者快速完成Kafka的安装和配置。 ... [详细]
  • SAP羞辱国产软件商:技术停在10年前
    SAP中国研究院总裁芮祥麟表示,国产软件厂商过于热衷概念炒作,技术水平停留在10年前的客户端架构水平。他认为,国内厂商推出基于SOA的产品或转型SAAS模式是不可能的,研发新架构需要时间。当前最热门的概念是云计算,芮祥麟呼吁国产厂商应该潜心研发底层架构。 ... [详细]
  • IT方面的论坛太多了,有综合,有专业,有行业,在各个论坛里混了几年,体会颇深,以前是论坛哪里人多 ... [详细]
  • CEPH LIO iSCSI Gateway及其使用参考文档
    本文介绍了CEPH LIO iSCSI Gateway以及使用该网关的参考文档,包括Ceph Block Device、CEPH ISCSI GATEWAY、USING AN ISCSI GATEWAY等。同时提供了多个参考链接,详细介绍了CEPH LIO iSCSI Gateway的配置和使用方法。 ... [详细]
  • 本文讲述了孙悟空写给白骨精的信件引发的思考和反省。孙悟空在信中对自己的行为进行了反思,认识到自己胡闹的行为并没有给他带来实际的收获。他也揭示了西天取经的真相,认为这是玉皇、菩萨设下的一场陷阱。他还提到了师傅的虚伪和对自己的实心话,以及自己作为师傅准备提拔的对象而被派下来锻炼的经历。他认为路上的九九八十一难也都是菩萨算计好的,唐僧并没有真正的危险。最后,他提到了观音菩萨在关键时刻的指导。这封信件引发了孙悟空对自己行为的思考和反省,对西天取经的目的和自己的角色有了更深入的认识。 ... [详细]
  • Windows2003 IIS上设置301定向,实现不带www域名跳转带www域名的方法
    打开IIS,建一个网站,主机头用不带www的域名,随便指向一个目录。然后在这个网站上点右键,属性--主目录--重定向到URL如图ÿ ... [详细]
  • 本文介绍了在Ubuntu下制作deb安装包及离线安装包的方法,通过备份/var/cache/apt/archives文件夹中的安装包,并建立包列表及依赖信息文件,添加本地源,更新源列表,可以在没有网络的情况下更新系统。同时提供了命令示例和资源下载链接。 ... [详细]
  • 本文讨论了读书的目的以及学习算法的重要性,并介绍了两个算法:除法速算和约瑟夫环的数学算法。同时,通过具体的例子和推理,解释了为什么x=x+k序列中的第一个人的位置为k,以及序列2和序列3的关系。通过学习算法,可以提高思维能力和解决问题的能力。 ... [详细]
author-avatar
甩小三弃小四
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有