本章内容:
- 视图
- 索引
- 存储过程、存储函数
- 触发器
- 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分支
语法 1:
IF 条件 THEN 语句 1;
语句 2;
END IF;
语法 2:
IF 条件 THEN 语句序列 1;
ELSE 语句序列 2;
END IF;
语法 3:
IF 条件 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循环
语法 1:
WHILE total <= 25000 LOOP
.. .
total : = total + salary;
END LOOP;
语法 2:
Loop
EXIT [when 条件];
……
End loop
语法 3:
FOR 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语句
- 创建maven项目,导入依赖包
<dependency>
<groupId>com.oracle</groupId>
<artifactId>ojdbc8</artifactId>
<version>12.2.0.1.0</version>
</dependency>
- 定义连接信息
String driver="oracle.jdbc.OracleDriver";
String url="jdbc:oracle:thin:@127.0.0.1:1521:orcl";
String username="scott";
String password="tiger";
- 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的存储过程
- 创建maven项目,导入依赖包
- 定义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;
- 定义连接信息
- 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();
}
}
}