zoukankan      html  css  js  c++  java
  • 29、Oralce(五)

    1)掌握PLSQL程序设计

    2)掌握存储过程,函数和触发器

    3)了解一些oralceSQL语句优化方案


    -------------------------------------------------------------------------------------准备篇


    col empno for 9999;
    col ename for a10;
    col job for a10;
    col mgr for 9999;
    col hiredate for a12;
    col sal for 9999;
    col comm for 9999;
    col deptno for 99;
    col tname for a40;
    set pagesize 80;


    -------------------------------------------------------------------------------------SQL对比PLSQL


    SQL99是什么
    (1)是操作所有关系型数据库的规则
    (2)是第四代语言
    (3)是一种结构化查询语言
    (4)只需发出合法合理的命令,就有对应的结果显示

    SQL的特点
    (1)交互性强,非过程化
    (2)数据库操纵能力强,只需发送命令,无需关注如何实现
    (3)多表操作时,自动导航简单,例如:
    select emp.empno,emp.sal,dept.dname
    from emp,dept
    where emp.deptno = dept.deptno
    (4)容易调试,错误提示,直接了当
    (5)SQL强调结果

    PLSQL是什么
    是专用于Oracle服务器,在SQL基础之上,添加了一些过程化控制语句,叫PLSQL
    过程化包括有:类型定义,判断,循环,游标,异常或例外处理。。。
    PLSQL强调过程

    为什么要用PLSQL
    因为SQL是第四代命令式语言,无法显示处理过程化的业务,所以得用一个过程化程序设计语言来弥补SQL的不足之处,
    SQL和PLSQL不是替代关系,是弥补关系

    PLSQL程序的完整组成结构如下:
    [declare]
    变量声明;
    变量声明;
    begin
    DML/TCL操作;
    DML/TCL操作;
    [exception]
    例外处理;
    例外处理;
    end;
    /
    注意:在PLSQL程序中,;号表示每条语句的结束,/表示整个PLSQL程序结束

    书写PLSQL的工具有:
    (1)SQLPLUS工具
    (2)SQLDeveloper工具
    (3)第三方工具(PLSQL & 其它)

    PLSQL与SQL执行有什么不同:
    (1)SQL是单条执行的
    (2)PLSQL是整体执行的,不能单条执行,整个PLSQL结束用/,其中每条语句结束用;号


    ------------------------------------------------------------------------------------PLSQL类型


    写一个PLSQL程序,输出"hello world"字符串,语法:dbms_output.put_line('需要输出的字符串');
    begin
    --向SQLPLUS客户端工具输出字符串
    dbms_output.put_line('hello 你好');
    end;
    /

    注意:
    dbms_output是oracle中的一个输出对象
    put_line是上述对象的一个方法,用于输出一个字符串自动换行

    设置显示PLSQL程序的执行结果,默认情况下,不显示PLSQL程序的执行结果,语法:set serveroutput on/off;
    set serveroutput on;

    使用基本类型变量,常量和注释,求10+100的和
    declare
    --定义变量
    mysum number(3) := 0;
    tip varchar2(10) := '结果是';
    begin
    /*业务算法*/
    mysum := 10 + 100;
    /*输出到控制器*/
    dbms_output.put_line(tip || mysum);
    end;
    /

    输出7369号员工姓名和工资,格式如下:7369号员工的姓名是SMITH,薪水是800,语法:使用表名.字段%type
    declare
    --定义二个变量,分别装姓名和工资
    pename emp.ename%type;
    psal emp.sal%type;
    begin
    --SQL语句
    --select ename,sal from emp where empno = 7369;
    --PLSQL语句,将ename的值放入pename变量中,sal的值放入psal变量中
    select ename,sal into pename,psal from emp where empno = 7369;
    --输出
    dbms_output.put_line('7369号员工的姓名是'||pename||',薪水是'||psal);
    end;
    /

    输出7788号员工姓名和工资,格式如下:7788号员工的姓名是SMITH,薪水是3000,语法:使用表名%rowtype
    declare
    emp_record emp%rowtype;
    begin
    select * into emp_record from emp where empno = 7788;
    dbms_output.put_line('7788号员工的姓名是'||emp_record.ename||',薪水是'||emp_record.sal);
    end;
    /

    何时使用%type,何时使用%rowtype?
    当定义变量时,该变量的类型与表中某字段的类型相同时,可以使用%type
    当定义变量时,该变量与整个表结构完全相同时,可以使用%rowtype,此时通过变量名.字段名,可以取值变量中对应的值
    项目中,常用%type


    ------------------------------------------------------------------------------------PLSQL判断


    使用if-else-end if显示今天星期几,是"工作日"还是"休息日"
    declare
    pday varchar2(10);
    begin
    select to_char(sysdate,'day') into pday from dual;
    dbms_output.put_line('今天是'||pday);
    if pday in ('星期六','星期日') then
    dbms_output.put_line('休息日');
    else
    dbms_output.put_line('工作日');
    end if;
    end;
    /

    从键盘接收值,使用if-elsif-else-end if显示"age<16","age<30","age<60","age<80"
    declare
    age number(3) := &age;
    begin
    if age < 16 then
    dbms_output.put_line('你未成人');
    elsif age < 30 then
    dbms_output.put_line('你青年人');
    elsif age < 60 then
    dbms_output.put_line('你奋斗人');
    elsif age < 80 then
    dbms_output.put_line('你享受人');
    else
    dbms_output.put_line('未完再继');
    end if;
    end;
    /


    -------------------------------------------------------------------------------------PLSQL循环


    使用loop循环显示1-10
    declare
    i number(2) := 1;
    begin
    loop
    --当i>10时,退出循环
    exit when i>10;
    --输出i的值
    dbms_output.put_line(i);
    --变量自加
    i := i + 1;
    end loop;
    end;
    /

    使用while循环显示1-10
    declare
    i number(2) := 1;
    begin
    while i<11
    loop
    dbms_output.put_line(i);
    i := i + 1;
    end loop;
    end;
    /

    使用while循环,向emp表中插入999条记录
    declare
    i number(4) := 1;
    begin
    while( i < 1000 )
    loop
    insert into emp(empno,ename) values(i,'哈哈');
    i := i + 1;
    end loop;
    end;
    /

    使用while循环,从emp表中删除999条记录
    declare
    i number(4) := 1;
    begin
    while i<1000
    loop
    delete from emp where empno = i;
    i := i + 1;
    end loop;
    end;
    /

    使用for循环显示20-30
    declare
    i number(2) := 20;
    begin
    for i in 20 .. 30
    loop
    dbms_output.put_line(i);
    end loop;
    end;
    /


    -------------------------------------------------------------------------------------PLSQL游标


    什么是光标/游标/cursor
    类似于JDBC中的ResultSet对象的功能,从上向下依次获取每一记录的内容

    使用无参光标cursor,查询所有员工的姓名和工资【如果需要遍历多条记录时,使用光标cursor,无记录找到使用cemp%notfound】
    declare
    --定义游标
    cursor cemp is select ename,sal from emp;
    --定义变量
    vename emp.ename%type;
    vsal emp.sal%type;
    begin
    --打开游标,这时游标位于第一条记录之前
    open cemp;
    --循环
    loop
    --向下移动游标一次
    fetch cemp into vename,vsal;
    --退出循环,当游标下移一次后,找不到记录时,则退出循环
    exit when cemp%notfound;
    --输出结果
    dbms_output.put_line(vename||'--------'||vsal);
    end loop;
    --关闭游标
    close cemp;
    end;
    /

    使用带参光标cursor,查询10号部门的员工姓名和工资
    declare
    cursor cemp(pdeptno emp.deptno%type) is select ename,sal from emp where deptno=pdeptno;
    pename emp.ename%type;
    psal emp.sal%type;
    begin
    open cemp(&deptno);
    loop
    fetch cemp into pename,psal;
    exit when cemp%notfound;
    dbms_output.put_line(pename||'的薪水是'||psal);
    end loop;
    close cemp;
    end;
    /

    使用无参光标cursor,真正给员工涨工资,ANALYST涨1000,MANAGER涨800,其它涨400,要求显示编号,姓名,职位,薪水
    declare
    cursor cemp is select empno,ename,job,sal from emp;
    pempno emp.empno%type;
    pename emp.ename%type;
    pjob emp.job%type;
    psal emp.sal%type;
    begin
    open cemp;
    loop
    fetch cemp into pempno,pename,pjob,psal;
    --循环退出条件一定要写
    exit when cemp%notfound;
    if pjob='ANALYST' then
    update emp set sal = sal + 1000 where empno = pempno;
    elsif pjob='MANAGER' then
    update emp set sal = sal + 800 where empno = pempno;
    else
    update emp set sal = sal + 400 where empno = pempno;
    end if;
    end loop;
    commit;
    close cemp;
    end;
    /


    -------------------------------------------------------------------------------------PLSQL例外


    使用oracle系统内置例外,演示除0例外【zero_divide】
    declare
    myresult number;
    begin
    myresult := 1/0;
    dbms_output.put_line(myresult);
    exception
    when zero_divide then
    dbms_output.put_line('除数不能为0');
    delete from emp;
    end;
    /

    使用oracle系统内置例外,查询100号部门的员工姓名,演示没有找到数据【no_data_found】
    declare
    pename varchar2(20);
    begin
    select ename into pename from emp where deptno = 100;
    dbms_output.put_line(pename);
    exception
    when NO_DATA_FOUND then
    dbms_output.put_line('查无该部门员工');
    insert into emp(empno,ename) values(1111,'ERROR');
    end;
    /

    使用用户自定义例外,使用光标cursor,查询10/20/30/100号部门的员工姓名,演示没有找到数据【nohave_emp_found】


    ------------------------------------------------------------------------------------存储过程概念


    什么是存储过程【procedure】?

    为什么要用存储过程?
    (1)PLSQL每次执行都要整体运行一遍,才有结果
    (2)PLSQL不能将其封装起来,长期保存在oracle服务器中
    (3)PLSQL不能被其它应用程序调用,例如:Java

    存储过程与PLSQL是什么关系?


    --------------------------------------------------------存储过程


    创建无参存储过程hello,无返回值,语法:create or replace procedure 过程名 as PLSQL程序

    删除存储过程hello,语法:drop procedure 过程名

    调用存储过程方式一,exec 存储过程名

    调用存储过程方式二,PLSQL程序

    调用存储过程方式三,Java程序

    创建有参存储过程raiseSalary(编号),为7369号员工涨10%的工资,演示in的用法,默认in,大小写不敏感

    创建有参存储过程findEmpNameAndSalAndJob(编号),查询7788号员工的的姓名,职位,月薪,返回多个值,演示out的用法

    什么情况下用exec调用,什么情况下用PLSQL调用存储过程?

    用存储过程,写一个计算个人所得税的功能


    -------------------------------------------------------------------------------------存储函数


    创建无参存储函数getName,有返回值,语法:create or replace function 函数名 return 返回类型 as PLSQL程序段

    删除存储函数getName,语法:drop function 函数名

    调用存储函数方式一,PLSQL程序

    调用存储函数方式二,Java程序

    创建有参存储函数findEmpIncome(编号),查询7369号员工的年收入,演示in的用法,默认in

    创建有参存储函数findEmpNameAndJobAndSal(编号),查询7788号员工的的姓名(return),职位(out),月薪(out),返回多个值


    -------------------------------------------------------------------------------------过程函数适合场景


    声明:适合不是强行要你使用,只是优先考虑

    什么情况下【适合使用】存储过程?什么情况下【适合使用】存储函数?

    【适合使用】存储过程:

    【适合使用】存储函数:

    什么情况【适合使用】过程函数,什么情况【适合使用】SQL?

    【适合使用】过程函数:
    》需要长期保存在数据库中
    》需要被多个用户重复调用
    》业务逻辑相同,只是参数不一样
    》批操作大量数据,例如:批量插入很多数据

    【适合使用】SQL:
    》凡是上述反面,都可使用SQL
    》对表,视图,序列,索引,等这些还是要用SQL


    -------------------------------------------------------------------------------------触发器


    什么是触发器【Trigger】?

    为什么要用触发器?

    创建语句级触发器insertEmpTrigger,当对表【emp】进行增加【insert】操作前【before】,显示"hello world"

    删除触发器insertEmpTrigger,语法:drop trigger 触发器名

    使用insert语句插入一条记录,引起insertEmpTrigger触发器工作

    使用insert语句插入N条记录,引起insertEmpTrigger触发器工作

    创建语句级触发器deleteEmpTrigger,当对表【emp】进行删除【delete】操作后【after】,显示"world hello"

    使用delete语句删除一条记录,引起deleteEmpTrigger触发器工作

    使用delete语句删除N条记录,引起deleteEmpTrigger触发器工作

    星期一到星期五,且9-20点能向数据库emp表插入数据,否则使用函数抛出异常,
    语法:raise_application_error('-20000','例外原因')

    创建行级触发器checkSalaryTrigger,涨后工资这一列,确保大于涨前工资,语法:for each row/:new.sal/:old.sal

    删除触发器,表还在吗?

    将表丢到回收站,触发器还在吗?

    当闪回表后,触发器会在吗?

    彻底删除表,触发器会在吗?


    -------------------------------------------------------------------------------------oracleSQL优化方案


    为什么要Oracle优化:
    随着实际项目的启动,Oracle经过一段时间的运行,最初的Oracle设置,会与实际Oracle运行性能会有一些差异,这时我们 就需要做一个优化调整。

    Oracle优化这个课题较大,可分为四大类:
    》主机性能
    》内存使用性能
    》网络传输性能
    》SQL语句执行性能【程序员】

    下面列出一些oracleSQL优化方案:


    (01)选择最有效率的表名顺序(笔试常考)
    ORACLE的解析器按照从右到左的顺序处理FROM子句中的表名,
    FROM子句中写在最后的表将被最先处理,
    在FROM子句中包含多个表的情况下,你必须选择记录条数最少的表放在最后,
    如果有3个以上的表连接查询,那就需要选择那个被其他表所引用的表放在最后。
    例如:查询员工的编号,姓名,工资,工资等级,部门名
    select emp.empno,emp.ename,emp.sal,salgrade.grade,dept.dname
    from salgrade,dept,emp
    where (emp.deptno = dept.deptno) and (emp.sal between salgrade.losal and salgrade.hisal)
    1)如果三个表是完全无关系的话,将记录和列名最少的表,写在最后,然后依次类推
    2)如果三个表是有关系的话,将引用最多的表,放在最后,然后依次类推


    (02)WHERE子句中的连接顺序(笔试常考)
    ORACLE采用自右而左的顺序解析WHERE子句,根据这个原理,表之间的连接必须写在其他WHERE条件之左,
    那些可以过滤掉最大数量记录的条件必须写在WHERE子句的之右。
    例如:查询员工的编号,姓名,工资,部门名
    select emp.empno,emp.ename,emp.sal,dept.dname
    from emp,dept
    where (emp.deptno = dept.deptno) and (emp.sal > 1500)

    (03)SELECT子句中避免使用*号
    ORACLE在解析的过程中,会将*依次转换成所有的列名,这个工作是通过查询数据字典完成的,这意味着将耗费更多的时间
    select empno,ename from emp;

    (04)使用DECODE函数来减少处理时间
    使用DECODE函数可以避免重复扫描相同记录或重复连接相同的表

    (05)整合简单,无关联的数据库访问

    (06)用TRUNCATE替代DELETE

    (07)尽量多使用COMMIT
    因为COMMIT会释放回滚点

    (08)用WHERE子句替换HAVING子句
    WHERE先执行,HAVING后执行

    (09)多使用内部函数提高SQL效率

    (10)使用表的别名
    salgrade s

    (11)使用列的别名
    ename e

    (12)用索引提高效率
    在查询中,善用索引

    (13)字符串型,能用=号,不用like
    因为=号表示精确比较,like表示模糊比较

    (14)SQL语句用大写的
    因为Oracle服务器总是先将小写字母转成大写后,才执行
    在eclipse中,先写小写字母,再通过ctrl+shift+X转大写;ctrl+shift+Y转小写

    (15)避免在索引列上使用NOT
    因为Oracle服务器遇到NOT后,他就会停止目前的工作,转而执行全表扫描

    (16)避免在索引列上使用计算
    WHERE子句中,如果索引列是函数的一部分,优化器将不使用索引而使用全表扫描,这样会变得变慢
    例如,SAL列上有索引,
    低效:
    SELECT EMPNO,ENAME
    FROM EMP
    WHERE SAL*12 > 24000;
    高效:
    SELECT EMPNO,ENAME
    FROM EMP
    WHERE SAL > 24000/12;

    (17)用 >= 替代 >
    低效:
    SELECT * FROM EMP WHERE DEPTNO > 3
    首先定位到DEPTNO=3的记录并且扫描到第一个DEPT大于3的记录
    高效:
    SELECT * FROM EMP WHERE DEPTNO >= 4
    直接跳到第一个DEPT等于4的记录

    (18)用IN替代OR
    select * from emp where sal = 1500 or sal = 3000 or sal = 800;
    select * from emp where sal in (1500,3000,800);

    (19)总是使用索引的第一个列
    如果索引是建立在多个列上,只有在它的第一个列被WHERE子句引用时,优化器才会选择使用该索引
    当只引用索引的第二个列时,不引用索引的第一个列时,优化器使用了全表扫描而忽略了索引
    create index emp_sal_job_idex
    on emp(sal,job);
    ----------------------------------
    select *
    from emp
    where job != 'SALES';

    (20)避免改变索引列的类型,显示比隐式更安全
    当字符和数值比较时,ORACLE会优先转换数值类型到字符类型
    select 123 || '123' from dual;


  • 相关阅读:
    vim复制
    嵌入式Linux学习(二)
    (Java实现) 洛谷 P1042 乒乓球
    (Java实现) 洛谷 P1042 乒乓球
    (Java实现) 洛谷 P1071 潜伏者
    (Java实现) 洛谷 P1071 潜伏者
    (Java实现) 洛谷 P1025 数的划分
    (Java实现)洛谷 P1093 奖学金
    (Java实现)洛谷 P1093 奖学金
    Java实现 洛谷 P1064 金明的预算方案
  • 原文地址:https://www.cnblogs.com/GJ-ios/p/6045551.html
Copyright © 2011-2022 走看看