三、Oracle进阶

本章内容:

  1. 视图
  2. 索引
  3. 存储过程、存储函数
  4. 触发器
  5. java操作oracle的sql、存储过程

1.视图

视图就是封装了一条复杂查询的语句。

语法 1.:CREATE VIEW 视图名称 AS 子查询
语法 2:CREATE OR REPLACE VIEW 视图名称 AS 子查询
语法 3:CREATE OR REPLACE VIEW 视图名称 AS 子查询 WITH READ ONLY( WITH READ ONLY代表只读视图)

—视图的作用?
—第一:视图可以屏蔽掉一些敏感字段。
—第二:保证总部和分部数据及时统一。

---1.视图
---视图的概念:视图就是提供一个查询的窗口,所有数据来自于原表。
create view view01 as select * from person where deptno =20;
select * from view01;

---查询语句创建表(可以将其他用用户表数据,来创建一个表)
create table emp as   select * from scott.emp;
create table dept as   select * from scott.dept;

---创建视图【必须有dba权限】
select * from emp;
create view view_emp as select * from emp where deptno =20;

---查询视图
select * from view_emp;

---修改视图[不推荐]
update view_emp set job='CLERK' where ename='JONES';
commit;
---创建只读视图
create view view_emp_read as select * from emp with read only;
---视图的作用?
---第一:视图可以屏蔽掉一些敏感字段。
---第二:保证总部和分部数据及时统一。

2.索引

索引是用于加速数据存取的数据对象。合理的使用索引可以大大降低 i/o 次数,从而提高数据访问性能。

  • 单列索引:单列索引是基于单个列所建立的索引
    CREATE index 索引名 on 表名(列名)
  • 复合索引:复合索引是基于两个列或多个列的索引。在同一张表上可以有多个索引,但是 要求列的组合必须不同
    CREATE index 索引名 on 表名(列名1,列名2)

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

---2.索引
--索引的概念:索引就是在表的列上构建一个二叉树
----达到大幅度提高查询效率的目的,但是索引会影响增删改的效率。
---单列索引
---创建单列索引
create index index_emp_ename on  emp(ename);
---单列索引触发规则,条件必须是索引列中的原始值。
---单行函数,模糊查询,都会影响索引的触发。
select * from emp where ename ='WARD';
---复合索引
---创建复合索引
create index index_emp_empno_ename on emp(empno,ename);
---复合索引中第一列为优先检索列
---如果要触发复合索引,必须包含有优先检索列中的原始值。
select * from emp where empno='7369';     ---触发单例索引
select * from emp where empno='7369' and ename ='SMITH'; --触发符合索引
select * from emp where empno='7369' or ename ='SMITH'; ---不触发索引,or相当于两条查询,条件是ename ='SMITH'的时候,没有优先检索项,不触发索引
select * from emp where  ename ='SMITH'; --不触发索引,没有优先检索项


3.pl/sql 基本语法[了解]

PL/SQL(Procedure Language/SQL)
PLSQL 是 Oracle 对 sql 语言的过程化扩展,指在 SQL 命令语言中增加了过程处理语句(如分支、循环等),使 SQL 语言具有过程处理能力。把 SQL 语言的数据操纵能力与过程语言的数据处理能力结合起来,使得 PLSQL 面向过程但比过程语言简单、高效、灵活和实用。

3.1pl/sql的程序语法

程序语法:

 
declare 
	说明部分(变量说明,游标申明,例外说明 〕 
begin 
	语句序列(DML 语句〕… 
exception 
	例外处理语句
End;
---声明方法
---赋值操作可以使用:=也可以使用into查询语句赋值
declare
       id number(2):=10;
       sname varchar2(10):= '小明';
       ena emp.ename%type;---引用性变量,可以引用查询到的变量
       emprow emp%rowtype; ---记录性变量,可以引用查询到的实体类
begin
       dbms_output.put_line(id);---dbms_output.put_line():打印输出
       dbms_output.put_line(sname);
       dbms_output.put_line(ena);
       select ename into ena from emp where empno =7788;   ---将查询到的值赋值给变量ename   
       dbms_output.put_line(ena);  
       select * into emprow from emp where empno =7788;    ---将查询到的实体赋值给emprow,可以通过emprow.属性  获取值
       dbms_output.put_line(emprow.ename||'的工作为:'||emprow.job);  ---字符串的连接不用 +,而是用||
     --  dbms_output.put_line(emprow);
end;                        ---声明方法结束之后,必须要 ;

3.2常量和变量定义

● 变量的基本类型就是 oracle 中的建表时字段的变量如 char, varchar2, date, number, boolean, long
● 引用变量
Myname emp.ename%type; 引用型变量,即 my_name 的类型与 emp 表中 ename 列的类型一样 ,在 sql中使用 into 来赋值
● 记录型变量
Emprec emp%rowtype; 记录变量分量的引用 emp_rec.ename:=‘ADAMS’;

3.3 if分支

语法 1IF 条件 THEN 语句 1; 
  语句 2; 
  END IF; 
语法 2IF 条件 THEN 语句序列 1ELSE 语句序列 2END IF; 
语法 3IF 条件 THEN 语句; 
  ELSIF 语句 THEN 语句;
  ELSE 语句; 
  END IF;
---pl/sql中的if判断
---输入小于18的数字,输出未成年
---输入大于18小于40的数字,输出中年人
---输入大于40的数字,输出老年人
declare
       age number(3):=&ageage;                     
begin
       if age<18 then
         dbms_output.put_line('未成年');       ---每一个if的 后面都需要  ;
       elsif age<40 then
         dbms_output.put_line('中年人');
       else 
         dbms_output.put_line('老年人');
       end if;  
end;

3.4 loop循环

语法 1WHILE total <= 25000 LOOP
  .. .
  total : = total + salary;
  END LOOP;
语法 2Loop
  EXIT [when 条件];
  ……
  End loop
语法 3FOR I IN 1 . . 3 LOOP
  语句序列 ;
  END LOOP ;
---pl/sql中的loop循环
---用三种方式:循环输出1到10是个数字
---while循环
declare
  i number(3):=1;
begin
  while i<11 loop
    dbms_output.put_line(i);
    i:=i+1;
    end loop;
end;
---exit循环
declare
    i number(3):=1;
begin
    loop
      exit when i>10;
      dbms_output.put_line('i:'||i);
      i:=i+1;
    end loop;
end;


---for循环
declare
    i number(3) :=1;
begin
    for i in 1..10 loop
        dbms_output.put_line('i:'||i);  
    end loop;
end;

3.5 游标

在写 java 程序中有集合的概念,那么在 pl/sql 中也会用到多条记录,这时候我们就要用到游标,游标可以存储查询返回的多条数据。

语法;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 列类型一致:

---游标:可以存放多个对象,多行记录。
---输出emp表中所有员工的姓名
declare
    cursor emps is select * from emp;  ---1.定义游标
    emprow emp%rowtype;
begin
    open emps;      ---2.打开游标
         loop
           fetch emps into emprow;   ---3.取一行游标的值
           exit when emps%notfound;    ----游标的结束方式
           dbms_output.put_line(emprow.empno||' - '||emprow.ename);
         end loop;
    close emps;      ---4.关闭游标
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;
           dbms_output.put_line('给员工【'||en||'】涨工资');
           update emp set sal=sal+100 where empno =en;
           commit;
         end loop;
    close c2;
end;

4、存储过程和存储函数

4.1 存储过程

存储过程(Stored Procedure)是在大型数据库系统中,一组为了完成特定功能的 SQL 语句集,经编译后存储在数据库中,用户通过指定存储过程的名字并给出参数(如果该存储过程带有参数)来执行它。

语法:

create [or replace] PROCEDURE 过程名[(参数名 in/out 数据类型)]   --in可以省略
AS 
begin
   PLSQL 子程序体;
End;

--------------------或则

create [or replace] PROCEDURE 过程名[(参数名 in/out 数据类型)] 
is
begin
   PLSQL 子程序体;
End 过程名;

---存储过程
--存储过程:存储过程就是提前已经编译好的一段pl/sql语言,放置在数据库端
--------可以直接被调用。这一段pl/sql一般都是固定步骤的业务。

----给指定员工涨100块钱
-------定义一个存储过程:p1
---存储过程、存储函数的参数的数据类型是不可用定义长度的
---创建完存储过程,我们可以在左侧【Procedures】视图下找到对应的存储过程,如果图标带红,则是创建存储过程失败了。
create or replace procedure p1(eno emp.empno%type)  --未加in、out的数据默认是输入参数,加上out是输出参数,
is
begin
       dbms_output.put_line('员工【'||eno||'】涨工资');   --每一条语句都需要用 ;隔开
       update emp set sal=sal +100 where empno =eno;
       commit;
end;
-------存储过程调用:
declare 
begin
  p1(7788);
end;

select * from emp where empno = 7788;

4.2 存储函数

存储函数的语法:

create or replace function 函数名(Name in type, Name in type, ...) return 数据类型 is
   结果变量 数据类型;
begin
 
   return(结果变量);
end 函数名;
----存储函数
----通过存储函数实现计算指定员工的年薪
----存储过程和存储函数的参数都不能带长度
----存储函数的返回值类型不能带长度
create or replace function func_Yearval(eno emp.empno%type) return number
is
   res number(10);
begin
   select sal*12 + nvl(comm,0) into res from emp where empno =eno;
  return res;
end;

----测试func_Yearval
----存储函数在调用的时候,返回值需要接收。
declare
  s number(10);
begin
  s:=func_Yearval(7788);
  dbms_output.put_line(s);
end;
  
  
---out类型参数如何使用
---使用存储过程来算年薪
create or replace procedure pro_Yearval(eno in emp.empno%type  ,yearVal out number)
is
  salYear number(10);
  comYear emp.comm%type;
begin
  select sal*12,nvl(comm,0) into salYear,comYear from emp where empno = eno;
  yearVal:= salYear +comYear;
end;


---测试p_yearsal
declare
  yearVal number(10);
  
begin

  pro_Yearval(7788,yearVal);
  dbms_output.put_line(yearVal);
end;

----in和out类型参数的区别是什么?
---凡是涉及到into查询语句赋值或者:=赋值操作的参数,都必须使用out来修饰。

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

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

  • 语法区别:关键字不一样,
    ------------存储函数比存储过程多了两个return,(可以直接select 取到存储函数的返回值)
  • 本质区别:存储函数有返回值,而存储过程没有返回值。
    ----------如果存储过程想实现有返回值的业务,我们就必须使用out类型的参数。
    ----------即便是存储过程使用了out类型的参数,起本质也不是真的有了返回值,
    ----------而是在存储过程内部给out类型参数赋值,在执行完毕后,我们直接拿到输出类型参数的值。

----我们可以使用存储函数有返回值的特性,来自定义函数。
----而存储过程不能用来自定义函数。


----案例需求:查询出员工姓名,员工所在部门名称。
----案例准备工作:把scott用户下的dept表复制到当前用户下。

drop table dept;
create  table  dept as select * from scott.dept;
----使用传统方式来实现案例需求
select emp.ename,dept.dname
from emp,dept
where emp.deptno = dept.deptno;

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

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


5、触发器

数据库触发器是一个与表相关联的、存储的 PL/SQL 程序。每当一个特定的数据操作语句(Insert,update,delete)在指定的表上发出时,Oracle 自动地执行触发器中定义的语句序列。

触发器可用于
● 数据确认
● 实施复杂的安全性检查
● 做审计,跟踪表上所做的数据操作等
● 数据的备份和同步

触发器中触发语句与伪记录的值:

在这里插入图片描述

CREATE [or REPLACE] TRIGGER 触发器名
  {BEFORE | AFTER}
  {DELETE | INSERT | UPDATE [OF 列名]}
  ON 表名
  [FOR EACH ROW [WHEN(条件) ] ]
begin
  PLSQL 块 End 触发器名
---触发器,就是制定一个规则,在我们做增删改操作的时候,
----只要满足该规则,自动触发,无需调用。
----语句级触发器:不包含有for each row的触发器。
----行级触发器:包含有for each row的就是行级触发器。
-----------加for each row是为了使用:old或者:new对象或者一行记录。

---语句级触发器
----插入一条记录,输出一个新员工入职
create  or replace trigger trigger1
after insert on  person
declare
begin
  dbms_output.put_line('新员工入职  ');
end trigger1;

-----触发trigger1
insert into person(pid,pname)values(9,'勿忘勿');
---行级别触发器
---不能给员工降薪
---raise_application_error(-20001~-20999之间, '错误提示信息');
create or replace trigger trigger2 before
update on emp 
for each row
declare

begin
  if :old.sal>:new.sal then
    raise_application_error(-20001,'不能给员工降薪');
  end if;
end;

-----触发trigger2
update emp set sal=sal-1 where emp.empno=7788;

注意:oracle可以使用触发器实现主键自增。


----触发器实现主键自增。【行级触发器】
---分析:在用户做插入操作的之前,拿到即将插入的数据,
------给该数据中的主键列赋值。
create or replace trigger trigger_auto_increment 
before insert on person 
for each row
declare

begin
  select person_sequence.nextval into :new.pid from dual;
  --:new.pid = person_sequence.nextval;
end;
---测试trigger_auto_increment
select * from person;

insert into person(pid,pname)values(1,'王文武');
insert into person(pname)values('悟空');

6、java连接oracle

6.1 java操作oracle的sql语句

  1. 创建maven项目,导入依赖包
        <dependency>
            <groupId>com.oracle</groupId>
            <artifactId>ojdbc8</artifactId>
            <version>12.2.0.1.0</version>
        </dependency>
  1. 定义连接信息
String driver="oracle.jdbc.OracleDriver";
String url="jdbc:oracle:thin:@127.0.0.1:1521:orcl";
String username="scott";
String password="tiger";
  1. java代码
/**
* 连接oracle的sql操作数据库
*/
@Test
public void test01()  {
    Connection connection =null;
    ResultSet resultSet=null;
    PreparedStatement pstmt =null;
    try {
        Class.forName("oracle.jdbc.driver.OracleDriver");
        connection = DriverManager.getConnection(url, username, password);
        pstmt = connection.prepareStatement("select * from emp ");
        resultSet= pstmt.executeQuery();
        while(resultSet.next()){
            System.out.println(resultSet.getString(1)+", "+resultSet.getString(2));
        }
    } catch (SQLException e) {
        e.printStackTrace();
    } catch (ClassNotFoundException e) {
        e.printStackTrace();
    }finally {
        try {
            resultSet.close();
            pstmt.close();
            connection.close();
        } catch (SQLException e) {
            e.printStackTrace();
        }
    }
    }

6.2 java操作oracle的存储过程

  1. 创建maven项目,导入依赖包
  2. 定义oracle的存储过程:
---使用存储过程来算年薪
create or replace procedure pro_Yearval(eno in emp.empno%type  ,yearVal out number)
is
  salYear number(10);
  comYear emp.comm%type;
begin
  select sal*12,nvl(comm,0) into salYear,comYear from emp where empno = eno;
  yearVal:= salYear +comYear;
end;

  1. 定义连接信息
  2. java代码操作存储过程
/**
* 测试调用存储过程
*/
@Test
public void test02(){
    Connection connection = null;
    CallableStatement callableStatement=null;
    try{
        Class.forName(driver);
        connection = DriverManager.getConnection(url, username, password);
        callableStatement = connection.prepareCall("{call pro_Yearval(?,?)}");
        callableStatement.setInt(1,7788);
        callableStatement.registerOutParameter(2, OracleTypes.NUMBER);
        callableStatement.execute();
        System.out.println(callableStatement.getObject(2));
    }catch (Exception ex){
        ex.printStackTrace();
    }finally {
        try {
            callableStatement.close();
            connection.close();
        } catch (SQLException e) {
            e.printStackTrace();
        }
    }
    }

相关文章

学习编程是顺着互联网的发展潮流,是一件好事。新手如何学习...
IT行业是什么工作做什么?IT行业的工作有:产品策划类、页面...
女生学Java好就业吗?女生适合学Java编程吗?目前有不少女生...
Can’t connect to local MySQL server through socket \'/v...
oracle基本命令 一、登录操作 1.管理员登录 # 管理员登录 ...
一、背景 因为项目中需要通北京网络,所以需要连vpn,但是服...