Oracle_2

一、视图

视图:

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

1. 创建视图

CREATE VIEW 视图名称 AS 子查询;

范例1:

建立一个视图,此视图包括了 20 部门的全部员工信息

create view empvd20 as select * from emp t where t.deptno = 20;

视图创建完毕就可以使用视图来查询,查询出来的都是 20 部门的员工

使用视图查询:

select * from EMPVD20 t;

2. 创建或覆盖已存在的视图

CREATE OR REPLACE VIEW 视图名称 AS 子查询

如果视图已经存在我们可以使用语法 2 来创建视图,这样已有的视图会被覆盖。

create or replace view empvd20 as select * from emp t where t.deptno = 20;

3. 创建或覆盖已存在的视图并设置只读

CREATE OR REPLACE VIEW 视图名称 AS 子查询 WITH READ ONLY

设置视图为只读。

create or replace view empvd20 as select * from emp t where t.deptno = 20 with read only;

我们一般不会去修改视图。我们可以设置视图为只读。

二、索引

索引是用于加速数据存取的数据对象。

合理地使用索引可以大大降低 I/O 次数,从而提高数据访问性能。

索引有很多种,我们主要介绍常用的几种。

  1. 单列索引
  2. 复合索引

1. 为甚么索引会加快查询速度

图书馆:如果杂乱地放书的话检索起来就非常困难,所以将书分类,然后再建一个箱子,箱子里面放卡片,卡片里面可以按类查询,按书名查或者类别查,这样的话速度会快很多很多,这个就有点像索引。索引的好处就是提高你找到书的速度,但是正是因为你建了索引,就应该有人专门来维护索引,维护索引是要有时间精力的开销的,也就是说索引是不能乱建的,所以建索引有个原则:如果有一个字段如果不经常查询,就不要去建索引。现在把书变成我们的表,把卡片变成我们的索引,就知道为什么索引会快,为什么会有开销。

2. 创建索引

2.1 单列索引

单列索引是基于单个列所建立的索引,比如:

create index 索引名 on 表名(列名);

范例:给 person 表的name建立索引

create index pname_index on person(name);

2.2 复合索引

复合索引是基于两个列或多个列的索引。在同一张表上可以由多个索引,但是要求列的组合必须不同。

​ 比如:

create index emp_idx1 on emp(ename,job);
create index emp_idx2 on emp(job,ename);

范例:给 person 表创建一个 name 和 gender 的索引

create index pname_gender_index on person(name, gender);

3. 索引的使用原则

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

三、pl/sql 基本语法

什么是pl/sql?

PL/SQL(Procedure Language/SQL)

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

范例 1:为职工涨工资,每人涨 10%的工资。
update emp set sal=sal*1.1
范例 2:例 2: 按职工的职称长工资,总裁涨 1000元,经理涨800 元,其他人员涨 400 元。
这样的需求我们就无法使用一条 SQL来实现,需要借助其他程序来帮助完成,也可以使用 pl/sql。

1. pl/sql 程序语法

declare
	说明部分 (变量说明,游标申明,例外说明 〕
begin
	语句序列 (DML 语句〕…
exception
	例外处理语句
End;

2. 常量和变量定义

在程序的声明阶段可以来定义常量和变量。

:=:给变量赋值

  • 变量的基本类型就是 oracle 中的建表时字段的变量如 char, varchar2, date, number,boolean, long

    定义语法:

    变量名 数据类型(长度)

    例如:varl char(15);Psal number(9,2);
    说明变量名、数据类型和长度后用分号结束说明语句。
    常量定义:married constant boolean:=true

  • 引用变量

    例如:Myname emp.ename%type;
    引用型变量,即my_name 的类型与emp 表中 ename 列的类型一样
    在 sql中使用 into 来赋值:

    declare 
    	emprec emp.ename%type; -- 声明变量emprec的数据类型为emp表中ename的数据类型
    begin 
    	-- 将emp表中员工编号为7396的ename的值赋给变量emprec
    	select t.ename into emprec from emp t where t.emptno = 7396; 
    	dbms_output.put_line(emprec);
    end;
    
  • 记录型变量

    Emprec emp%rowtype;

    记录变量分量的引用
    emp_rec.ename:='ADAMS';

    declare 
    	p emp%rowtype; -- 声明变量p的数据类型为emp表的一行
    begin 
    	-- 将将emp表中员工编号为7396这行数据赋给变量emprec
    	select * into p from emp t where t.empno = 7369; 
    	dbms_output.put_line(p.ename || ' ' || p.sal);
    end;
    

3. if分支

语法1:

IF 条件 THEN 语句1;
	语句2;
END IF;

范例 1:

​ 如果从控制台输入 1 则输出我是 1

declare 
	pnum number := #
begin
	if pnum = 1 then
		dbms_output.put_line('我是1');
  end if;
end;

语法2:

IF 条件 THEN 语句序列1;
	ELSE 语句序列2;
END IF;

范例 2:

​ 如果从控制台输入 1 则输出我是 1否则输出我不是 1

declare 
	pnum number := #
begin
	if pnum = 1 then
		dbms_output.put_line('我是1');
	else
		dbms_output.put_line('我不是1');
  end if;
end;

语法3:

IF 条件 THEN 语句;
ELSE IF 语句 THEN 语句;
ELSE 语句;
END IF;

范例 3:

​ 判断人的不同年龄段 18岁以下是未成年人,18岁以上 40以下是成年人,40以上是老年人

declare
	mynum number := #
begin
	if mynum < 18 then
		dbms_output.put_line('未成年人');
	elsif mynum > 18 then 
		dbms_output.put_line('成年人呢');
	elsif mynum >= 40 then  
		dbms_output.put_line('来年人');
	end if;
end;

4. lOOP循环语句

语法1:

WHILE 条件 LOOP
	语句序列;
END LOOP;

范例:

​ 使用语法 1 输出 1 到10 的数字

declare 
  n number := 1;
begin
  while n <= 10 loop
        dbms_output.put_line(n);
        n := n+1;
  end loop;
end;

语法2:

LOOP
EXIT [WHEN 条件];
	语句序列;
END LOOP;

范例:

​ 使用语法 2 输出 1 到10 的数字

declare 
  n number := 1;
begin
  loop
    exit when n > 10;
         dbms_output.put_line(n);
        n := n+1;
    end loop;
end;

语法3:

FOR 条件 LOOP
 语句序列;
END LOOP;

范例:

​ 使用语法 3 输出 1 到10 的数字

declare 
    n number := 1;
begin
  for n in 1 .. 10 loop
      dbms_output.put_line(n);
  end loop;
end;

5. 游标 Cursor

在写Java程序中有集合的概念,那么在pl/sql中也会用到多条记录,这时候我们就需要用到游标。

游标可以存储查询返回的多条数据。

5.1 语法:

CURSOR 游标名称 [(参数名 数据类型. 参数名 数据类型......)] IS SELECT 语句;

​ 例如:

cursor c1 is select ename from emp;

5.2 使用步骤

  1. 打开游标:
    open 游标名;(打开游标进行查询)

  2. 取一行游标的值:

    fetch 游标名 into 变量名;(去一行到变量中)

  3. 关闭游标:

    close 游标名;(关闭游标释放资源)

  4. 游标的结束方式

    exit when 游标名%notfound;

**注意:**上面的变量名必须和表中对应的数据类型一致

范例 1:

​ 使用游标方式输出 emp 表中的员工编号和姓名

declare
	cursor pc is		-- 定义游标
		select * from emp;
	pemp emp%rowtype; 	-- 声明变量 pemp 数据类型为 emp表中的一行数据
begin
	open pc;			-- 打开游标
	loop				-- loop循环
	fetch pc into pemp;	 -- 取一行游标中的值到变量 pemp 中
	exit when pc%notfound; -- 定义关闭游标的方式
	dbms_output.put_line(pemp.empno || ' ' || pemp.ename); -- 
	end loop; -- 
	close pc; -- 关闭游标
end;

范例 2:

​ 按员工的工种涨工资,总裁 1000 元,经理涨 800 元其,他人员涨 400 元。
备份出一张新表为 myemp:create table myemp as select * from emp;

declare
	cursor pc is
		select * from myemp;
	addsal myemp.sal%type;
	pemp myemp%rowtype;
begin
	open pc;
	loop
        fetch pc into pemp;
        exit when pc%notfound;
        if pemp.job = 'PRESIDENT' then
            addsal := 1000;
        elsif pemp.job = 'MANAGER' then
            addsal := 800;
        else
            addsal := 400;
        end if;
	update myemp t set t.sal = t.sal + addsal where t.empno = pemp.empno;
	end loop;
	close pc;
end;

范例 3:

​ 写一段PL/SQL 程序,为部门号为 10 的员工涨工资。

declare
	cursor pc(dno myemp.deptno%type) is
		select empno from myemp where deptno = dno;
	pno myemp.empno%type;
begin
	open pc(20);
	loop
	fetch pc into pno;
	exit when pc%notfound;
	update myemp t set t.sal = t.sal + 1000 where t.empno = pno;
	end loop;
	close pc;
end;

四、存储过程

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

存储过程是数据库的一个重要对象,任何一个设计良好的数据库应用程序都应该用到存储过程。

1. 创建存储过程

语法:

CREATE [OR REPLACE] PROCEDURE 
	存储过程名称[(参数名 in/out 数据类型)]
AS
BEGIN
	PLSQL子程序体;
END;

-- 或者

CREATE [OR REPLACE] PROCEDURE 
	存储过程名称[(参数名 in/out 数据类型)]
IS
BEGIN
	PLSQL子程序体;
END 存储过程名称;

**范例:**创建一个输出 helloword 的存储过程

create or replace procedure helloword 
is
begin 
	dbms_output.put_line('hello world');
end helloworld;

2. 调用存储过程

在PL/SQL中调用存储过程

BEGIN
	helloworld;
END;

3. 涨工资范例

​ 给指定的员工涨 100 工资,并打印出涨前和涨后的工资
分析:我们需要使用带有参数的存储过程

create or replace procedure addSall(eno in number)
is
	pemp myemp%rowtype;
begin 
	select * into pemp form myemp where empno = eno;
	update myemp set sal = sal + 100 where empno = eno;
	dbms_output.put_line('涨工资前' || pemp.sal || '涨工资后' || (pemp.sal + 100));
end addSall;

-- 调用
begin
	addSall(eno => 7902);
	commit;
end;

五、存储函数

CREATE OR REPLACE FUNCTION 
	存储函数名(Name in type, Name in type ......) RETURN 
	数据类型 
IS 
	结果变量名 数据类型;
BEGIN
	......
	RETURN(结果变量);
END 存储函数名;

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

一般来讲,过程和函数的区别在于函数可以有一个返回值,而过程没有。

但过程和函数都可以通过 out 指定一个或多个输出参数。

我们可以利用 out 参数,在过程和函数中实现返回多个值。

范例:

​ 使用存储函数来查询指定员工的年薪

create or replace function 
	empincome(eno in emp.empno%type)
return 
	number
is
	psal emp.sal%type;
	pcomm emp.comm%type;
begin
	select t.sql, t.comm into psal, pcomm from emp t where t.empno = eno;
	return 
		psal * 12 + nvl(pcomm, 0);
end;

-- 调用
declare 
	yearSal number;
begin
	yearSal := empincome(7369);
	dbms_output.put_line(yearSal);
end;

使用存储过程来替换上面的例子

create or replace procedure 
	empincomep(eno in emp.empno%type, income out number)
is
	psal emp.sal%type;
	pcomm emp.comm%type;
begin
	select t.sql, t.comm into psal, pcomm from emp t where t.empno = eno;
	income := psal * 12 + nvl(pcomm, 0);
end empincomep;

-- 调用
declare 
	income number;
begin
	empincomp(7369, income);
	dbms_output.put_line(income);
end;

六、触发器

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

每当一个特定的数据操作语句(insert、update、delete)在制定的表上发出时,Oracle自动地执行触发器中定义的语句序列。

1. 触发器用处

  • 数据确认
  • 实施复杂的安全性检查
  • 做审计,跟踪表上所做的数据操作等
  • 数据的备份和同步

2. 触发器的类型

  • 语句级触发器

    在指定的操作语言操作之前或之后执行一次,不管这条语句影响了多少行。

  • 行级触发器

    触发语句作用的每一条记录都会被触发。在行级触发器中使用 old 和 new 伪记录变量,识别值的状态。

3. 触发器的使用

创建语法:

CREATE OR REPLACE TRIGGER
	触发器名称
	{BEFORE|AFTER}	
	{DELETE|INSERT|UPDATE[OF 列名]}
	ON 表名
BEGIN
	PLSQL 程序块
END 触发器名称;

**范例1:**插入员工后打印一句话“一个新员工插入成功”

create or replace triggert estTrigger
	after insert on person
declare
	-- local variables here
begin 
	dbms_output.put_line('插入一条员工信息');
end testTrigger;

**范例2:**不能在休息时间插入员工

create or replace trigger validInsertPerson
	before insert on person

declare
	weekend varchar2(10);
begin 
	select to_char(sysdate, 'day') into weekend from dual;
	if weekend in ('星期一') then
		raise_application_error(-20001, '不能在非法时间插入员工');
	end if;
end validInsertPerson;

在触发器中触发语句与伪记录变量的值

触发语句:old:new
insert所有字段都是空(null)将要插入的数据
update更新以前该行的值更新后的值
delete删除以前该行的值所有字段都是kong(null)

**范例3:**判断员工涨工资之后的工资的值一定要大于涨工资之前的工资

create or replace trigger addSal4p
	before update of sal on myemp
	for each row
begin 
	if :old.sal >= :new.sal then
		raise_application_error(-20002, '涨前的工资不能大于涨后的工资');
	end if;
end addSal4p;

-- 修改工资
update myemp t set t.sal = t.sal - 1;

​ 如果员工涨工资之后的工资小于了涨工资之前的工资
在这里插入图片描述

七、Java 程序调用存储过程

1. java 连接 oracle 的 的 jar

ojdbc14.jar

ojdbc6.jar

​ maven

​ pom.xml

<dependencies>
        <dependency>
            <groupId>com.oracle</groupId>
            <artifactId>ojdbc14</artifactId>
            <version>10.2.0.4.0</version>
            <scope>runtime</scope>
        </dependency>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.10</version>
            <scope>test</scope>
        </dependency>
    </dependencies>

2. 数据库连接参数

jdbc.oracle.driver=oracle.jdbc.OracleDriver
jdbc.oracle.url=jdbc:oracle:thin:@127.0.0.1:1521:orcl
jdbc.oracle.username=scott
jdbc.oracle.password=tiger

连接测试代码:

@Test
    public void javaCallOracle() throws Exception {
        //加载数据库驱动
        Class.forName("oracle.jdbc.driver.OracleDriver");
        //得到Connection连接
        Connection connection = DriverManager.getConnection("jdbc:oracle:thin:@192.168.88.6:1521:orcl", "itheima", "itheima");
        //得到预编译的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.getString("ename"));
        }
        //释放资源
        rs.close();
        pstm.close();
        connection.close();
    }

3. 实现存储过程的调用

3.1 定义存储过程

create or replace procedure proc_countyearsal(eno in emp.empno%type, esal out number)
AS
begin 
	select sal * 12 + nvl(comm, 0) into esal from emp where empno = eno;
end;

-- 掉用
declare
	esal number;
begin 
	proc_countyearsal(7839, esal);
	dbms_output.put_line(esal);
end;

3.2 存储过程调用

/**
 * java调用存储过程
 * {?= call <procedure-name>[(<arg1>,<arg2>, ...)]}   调用存储函数使用
 *  {call <procedure-name>[(<arg1>,<arg2>, ...)]}   调用存储过程使用
 * @throws Exception
 */
@Test
public void javaCallProcedure() throws Exception {
    //加载数据库驱动
    Class.forName("oracle.jdbc.driver.OracleDriver");
    //得到Connection连接
    Connection connection = DriverManager.getConnection("jdbc:oracle:thin:@192.168.88.6:1521:orcl", "itheima", "itheima");
    //得到预编译的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();
}

4. 存储函数调用

4.1 定义存储函数

4.2 存储函数调用

/**
 * java调用存储函数
 * {?= call <procedure-name>[(<arg1>,<arg2>, ...)]}   调用存储函数使用
 * {call <procedure-name>[(<arg1>,<arg2>, ...)]}   调用存储过程使用
 * @throws Exception
 */
@Test
public void javaCallFunction() throws Exception {
	//加载数据库驱动     				
	Class.forName("oracle.jdbc.driver.OracleDriver");
    //得到Connection连接
    Connection connection = DriverManager.getConnection("jdbc:oracle:thin:@192.168.88.6:1521:orcl", "itheima", "itheima");
    //得到预编译的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();
}

4. 存储函数调用

4.1 定义存储函数

4.2 存储函数调用

/**
 * java调用存储函数
 * {?= call <procedure-name>[(<arg1>,<arg2>, ...)]}   调用存储函数使用
 * {call <procedure-name>[(<arg1>,<arg2>, ...)]}   调用存储过程使用
 * @throws Exception
 */
@Test
public void javaCallFunction() throws Exception {
	//加载数据库驱动     				
	Class.forName("oracle.jdbc.driver.OracleDriver");
    //得到Connection连接
    Connection connection = DriverManager.getConnection("jdbc:oracle:thin:@192.168.88.6:1521:orcl", "itheima", "itheima");
    //得到预编译的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();
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值