Oracle的高级功能-视图+索引+pl/sql+游标+存储过程+存储函数+触发器+jdbc连接orcl

Oracle的高级功能

1.视图

视图就是封装了一条复杂查询的语句,提供一个查询的窗口,所有数据来自于原表

视图可以屏蔽掉一些敏感字段,保证总部和分部数据及时统一

  • 创建视图+查询视图
---创建视图【必须有dba权限】
alter session set current_schema = SYS;
grant create  view to SCOTT;
alter session set current_schema = SCOTT;
create view v_emp as select ename, job from emp;
---查询视图
select * from v_emp;
---修改视图[不推荐]
update v_emp set job='CLERK' where ename='ALLEN';
commit;
  • 创建只读视图
---创建只读视图
create view v_emp1 as select ename, job from emp with read only;
select * from v_emp1;
-- update v_emp1 set job='CLERK' where ename='ALLEN';

2.索引

索引是帮助数据库高效获取数据的数据对象。合理的使用索引可以大大降低 i/o 次数,从而提高数据访问性能。

提高查询效率的目的,但是会影响增删改的效率。索引B-和B+树原理请看索引篇

  • 查询索引
-- 查询出用户所有表的索引
select * from user_indexes;
-- 查询用户表的索引(非聚集索引)
select * from user_indexes where uniqueness='NONUNIQUE';
-- 查询用户表的主键(聚集索引)
select * from user_indexes where uniqueness='UNIQUE';
-- 查询表的索引
select t.*,i.index_type from user_ind_columns t,user_indexes i where t.index_name = i.index_name and t.table_name='NODE';
-- 查询表的主键
select cu.* from user_cons_columns cu, user_constraints au where cu.constraint_name = au.constraint_name and au.constraint_type = 'P' AND cu.table_name = 'NODE';
-- 查找表的唯一性约束(包括名称,构成列)
select column_name from user_cons_columns cu, user_constraints au where cu.constraint_name=au.constraint_name and cu.table_name='NODE';

2.1单列索引

---创建单列索引
create index idx_ename on emp(ename);
---单列索引触发规则,条件必须是索引列中的原始值。
---单行函数,模糊查询,都会影响索引的触发。
select * from emp where ename='SCOTT';

2.2复合索引

---创建复合索引
create index idx_enamejob on emp(ename, job);
---复合索引中第一列为优先检索列
---如果要触发复合索引,必须包含有优先检索列中的原始值。
select * from emp where ename='SCOTT' and job='xx';---触发复合索引
select * from emp where ename='SCOTT' or job='xx';---不触发索引
select * from emp where ename='SCOTT';---触发单列索引。

索引的使用原则

  • 在大表上建立索引才有意义
  • 在 where子句后面或者是连接条件上的字段建立索引
  • 表中数据修改频率高时不建议建立索引

3.pl/sql

Procedure Language/SQL,Oracle对sql的过程化扩展,高级语法,其他sql不具备的。

增加了过程处理语句(如分支、循 环),使 SQL 语言具有过程处理能力。

使得PLSQL 面向过程但比过程语言简单、高效、灵活和实用。本质上是面对过程

declare
 说明部分 (变量说明,游标申明,例外说明 〕
begin
 语句序列 (DML 语句〕…
exception
 例外处理语句
End;
---声明方法
---赋值操作可以使用:=也可以使用into查询语句赋值
declare
    i number(2) := 10;
    s varchar2(10) := '小明';
    ena emp.ename%type;---引用型变量
    emprow emp%rowtype;---记录型变量
begin
    dbms_output.put_line(i);
    dbms_output.put_line(s);
    select ename into ena from emp where empno = 7788;
    dbms_output.put_line(ena);
    select * into emprow from emp where empno = 7788;
    dbms_output.put_line(emprow.ename || '的工作为:' || emprow.job);
end;
  • if判断
---输入小于18的数字,输出未成年
---输入大于18小于40的数字,输出中年人
---输入大于40的数字,输出老年人
declare
    i number(3) := ⅈ
begin
    if i<18 then
        dbms_output.put_line('未成年');
    elsif i<40 then
        dbms_output.put_line('中年人');
    else
        dbms_output.put_line('老年人');
    end if;
end;
  • loop循环
-- -用三种方式输出1到10是个数字
-- -while循环
declare
    i number(2) := 1;
begin
  while i<11 loop
     dbms_output.put_line(i);
     i := i+1;
  end loop;
end;
---exit循环
declare
  i number(2):=1;
begin
  loop
    exit when i>10;
    dbms_output.put_line(i);
    i := i+1;
  end loop;
end;
---for循环
declare
begin
  for i in 1..10 loop
     dbms_output.put_line(i);
  end loop;
end;
  • 实际运用
-----给指定部门员工涨工资
declare
  cursor c2(eno emp.deptno%type)
  is select empno from emp where deptno = eno;
  en emp.empno%type;
begin
  open c2(10);
     loop
        fetch c2 into en;
        exit when c2%notfound;
        update emp set sal=sal+100 where empno=en;
        commit;
     end loop;
  close c2;
end;

4.游标cursor

在 pl/sql中也会用到多条记录,游标可以存储查询返回的多条数据。相当于in集合和=单列区别

---游标:可以存放多个对象,多行记录。
-- CURSOR 游标名 [ (参数名 数据类型,参数名 数据类型,...)] IS SELECT
cursor c1 is select ename from emp;
  • 游标的使用
打开游标: open c1; (打开游标执行查询)
取一行游标的值:fetch c1 into pjob; (取一行到变量中)
关闭游标: close c1;(关闭游标释放资源)
游标的结束方式 exit when c1%notfound
注意: 上面的 pjob 必须与 emp 表中的 job 列类型一致:
定义:pjob emp.empjob%type;
  • 实现
---输出emp表中所有员工的姓名
declare
  cursor c1 is select * from emp;
  emprow emp%rowtype;
begin
  open c1;
     loop
         fetch c1 into emprow;
         exit when c1%notfound;
         dbms_output.put_line(emprow.ename);
     end loop;
  close c1;
end;
-----给指定部门员工涨工资
declare
  cursor c2(eno emp.deptno%type)
  is select empno from emp where deptno = eno;
  en emp.empno%type;
begin
  open c2(10);
     loop
        fetch c2 into en;
        exit when c2%notfound;
        update emp set sal=sal+100 where empno=en;
        commit;
     end loop;
  close c2;
end;
----查询10号部门员工信息
select * from emp where deptno = 10;

5.存储过程

一组为了完成特定功能的 SQL 语句集

编译后存储在数据库中,用户通过指定存储过程的名字并给出参数(该存储过程带有参数)来执行它。

create [or replace] PROCEDURE 过程名[(参数名 in/out 数据类型)] 
AS
begin
 PLSQL 子程序体;
End;
----通过存储函数实现计算指定员工的年薪
----存储过程和存储函数的参数都不能带长度
----存储函数的返回值类型不能带长度
create or replace function f_yearsal(eno emp.empno%type) return number
is
  s number(10);
begin
  select sal*12+nvl(comm, 0) into s from emp where empno = eno;
  return s;
end;

----测试f_yearsal
----存储函数在调用的时候,返回值需要接收。
declare
  s number(10);
begin
  s := f_yearsal(7788);
  dbms_output.put_line(s);
end;
---out类型参数如何使用
----in和out类型参数的区别是什么?
---凡是涉及到into查询语句赋值或者:=赋值操作的参数,都必须使用out来修饰。
---使用存储过程来算年薪
create or replace procedure p_yearsal(eno emp.empno%type, yearsal out number)
is
   s number(10);
   c emp.comm%type;
begin
   select sal*12, nvl(comm, 0) into s, c from emp where empno = eno;
   yearsal := s+c;
end;

---测试p_yearsal
declare
  yearsal number(10);
begin
  p_yearsal(7788, yearsal);
  dbms_output.put_line(yearsal);
end;

6.存储函数

create or replace function 函数名(Name in type, Name in type, ...) return 数据类型 is
 结果变量 数据类型;
begin

 return(结果变量);
end 函数名;

存储过程和存储函数的区别

语法区别:关键字不一样,存储函数比存储过程多了两个return

本质区别:存储函数有返回值,而存储过程没有返回值。

如果存储过程想实现有返回值的业务,我们就必须使用out类型的参数。即便是存储过程使用了out类型的参数,起本质也不是真的有了返回值,而是在存储过程内部给out类型参数赋值,在执行完毕后,我们直接拿到输出类型参数的值。

  • 使用存储函数有返回值的特性,来自定义函数。存储过程不能用来自定义函数。
----案例需求:查询出员工姓名,员工所在部门名称。
----案例准备工作:把scott用户下的dept表复制到当前用户下。
create table dept as select * from scott.dept;
----使用传统方式来实现案例需求
select e.ename, d.dname
from emp e, dept d
where e.deptno=d.deptno;

----使用存储函数来实现提供一个部门编号,输出一个部门名称。
create or replace function fdna(dno dept.deptno%type) return dept.dname%type
is
  dna dept.dname%type;
begin
  select dname into dna from dept where deptno = dno;
  return dna;
end;

---使用fdna存储函数来实现案例需求:查询出员工姓名,员工所在部门名称。
select e.ename, fdna(e.deptno)
from emp e;

7.触发器

数据库触发器是一个与表相关联的、存储的 PL/SQL 程序。

每当一个特定的数据操作语句 (Insert,update,delete)在指定的表上发出时,自动执行定义的语句序列。

触发器,就是制定一个规则,做增删改操作的时候,只要满足该规则,自动触发,无需调用。

  • 语句级触发器:不包含有for each row的触发器
---语句级触发器
----插入一条记录,输出一个新员工入职
create or replace trigger t1
after
insert
on person
declare

begin
  dbms_output.put_line('一个新员工入职');
end;
---触发t1
insert into person values (1, '小红');
commit;
select * from person;
  • 行级触发器:包含有for each row的就是行级触发器
---行级别触发器
---不能给员工降薪
---raise_application_error(-20001~-20999之间, '错误提示信息');
create or replace trigger t2
before
update
on emp
-----------加for each row是为了使用:old或者:new对象或者一行记录。
for each row
declare

begin
  if :old.sal>:new.sal then
     raise_application_error(-20001, '不能给员工降薪');
  end if;
end;
----触发t2
select * from emp where empno = 7788;
update emp set sal=sal-1 where empno = 7788;
commit;
----触发器实现主键自增。【行级触发器】
---分析:在用户做插入操作的之前,拿到即将插入的数据,
------给该数据中的主键列赋值。
create or replace trigger auid
before
insert
on person
for each row
declare

begin
  select s_person.nextval into :new.pid from dual;
end;
--查询person表数据
select * from person;
---使用auid实现主键自增
insert into person (pname) values ('a');
commit;
insert into person values (1, 'b');
commit;

8.JavaAPI-JDBC调用Oracle

创建maven工程

  • pom.xml

<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0modelVersion>

    <groupId>com.ljgroupId>
    <artifactId>jdbc_oracleartifactId>
    <version>1.0-SNAPSHOTversion>


    <dependencies>
        <dependency>
            <groupId>com.oraclegroupId>
            <artifactId>ojdbc14artifactId>
            <version>10.2.0.4.0version>
        dependency>
        <dependency>
            <groupId>junitgroupId>
            <artifactId>junitartifactId>
            <version>4.10version>
            <scope>testscope>
        dependency>
    dependencies>
project>
  • 测试
package com.lj.oracle;

import oracle.jdbc.OracleTypes;
import org.junit.Test;

import java.sql.*;

public class OracleDemo {
    String driver = "oracle.jdbc.driver.OracleDriver";
    String url="jdbc:oracle:thin:@localhost:1521:orcl";
    String username="scott";
    String password="tiger";
    @Test
    public void javaCallOracle() throws Exception {
        //加载数据库驱动
        Class.forName(driver);
        //得到Connection连接
        Connection connection = DriverManager.getConnection(url, username, password);
        //得到预编译的Statement对象
        PreparedStatement pstm = connection.prepareStatement("select * from emp where empno = ?");
        //给参数赋值
        pstm.setObject(1, 7788);
        //执行数据库查询操作
        ResultSet rs = pstm.executeQuery();
        //输出结果
        while(rs.next()){
            System.out.println(rs);
        }
        //释放资源
        rs.close();
        pstm.close();
        connection.close();
    }

    /**
     * java调用存储过程
     * {?= call [(,, ...)]}   调用存储函数使用
     *  {call [(,, ...)]}   调用存储过程使用
     * @throws Exception
     */
    @Test
    public void javaCallProcedure() throws Exception {
        //加载数据库驱动
        Class.forName(driver);
        //得到Connection连接
        Connection connection = DriverManager.getConnection(url, username, password);
        //得到预编译的Statement对象
        CallableStatement pstm = connection.prepareCall("{call p_yearsal(?, ?)}");
        //给参数赋值
        pstm.setObject(1, 7788);
        pstm.registerOutParameter(2, OracleTypes.NUMBER);
        //执行数据库查询操作
        pstm.execute();
        //输出结果[第二个参数]
        System.out.println(pstm.getObject(2));
        //释放资源
        pstm.close();
        connection.close();
    }


    /**
     * java调用存储函数
     * {?= call [(,, ...)]}   调用存储函数使用
     *  {call [(,, ...)]}   调用存储过程使用
     * @throws Exception
     */
    @Test
    public void javaCallFunction() throws Exception {
        //加载数据库驱动
        Class.forName(driver);
        //得到Connection连接
        Connection connection = DriverManager.getConnection(url, username, password);
        //得到预编译的Statement对象
        CallableStatement pstm = connection.prepareCall("{?= call f_yearsal(?)}");
        //给参数赋值
        pstm.setObject(2, 7788);
        pstm.registerOutParameter(1, OracleTypes.NUMBER);
        //执行数据库查询操作
        pstm.execute();
        //输出结果[第一个参数]
        System.out.println(pstm.getObject(1));
        //释放资源
        pstm.close();
        connection.close();
    }
}

提取配置

  • db.properties
jdbc.driver=oracle.jdbc.driver.OracleDriver
jdbc.url=jdbc:oracle:thin:@localhost:1521:orcl
jdbc.username=lj
jdbc.password=lj

你可能感兴趣的:(SQL和数据库,数据库,oracle,java)