Oracle第二天
整体安排(3天)
第一天:Oracle的安装配置(服务端和客户端),SQL增强(单表查询)。
第二天:SQL增强(多表查询、子查询、伪列-分页),数据库对象(表、约束、序列),Oracle基本体系结构、表空间、用户和权限 ,视图、同义词
第三天:数据库对象(索引、数据字典),PLSQL编程、存储过程,数据库备份和还原。
今天的安排:
多表关联查询(内连接(等值和不等值)、外连接(左外、右外、全外)、自连接,Oracle的写法) SQL增强-子查询(分为单行子查询和多行子查询。) 伪列(rowid和rownum-Oracle分页)--查询结束 数据处理(包括插入数据(批量插入语法等)、更新数据、删除数据(高水位,truncate和delete区别)。 数据库事务,包括事务的开启和结束、事务保留点等。 数据库对象--表,包括创建表(复制表语法)、修改表、删除表 了解一下表的约束(新增check约束) 序列,包括语法、应用、注意事项。 Oracle的体系结构-几个概念 表空间的管理,包括概念、创建表空间等。 用户和权限相关(普通用户只需要两个角色) 视图:概念、语法、作用 同义词:概念、语法、作用
多表查询也称之为关联查询、多表关联查询等,主要是指通过多个表的关联来获取数据的一种方式。
一对多:A表的一行数据,对应B表中的多条。如:一个部门可以对应多个员工.
多对一:B表中的多条对应A表的一行数据.如:多个员工对应一个部门.
多对多:学生和选修课表----学生和课程对应表。
一对一:人员基本信息和人员信息扩展表。
笛卡尔集对于我们数据库的数据查询结果的影响:
数据冗余。---笛卡尔集并不是我们所需要的数据. 效率问题:导致数量级的增长。100w *100w,====》1w亿。如果你在查询大量数据的时候,不注意这个笛卡尔集的话,会导致你的查询结果时间非常非常非常长,还会导致数据库故障。因此,在实际运行环境下,应避免使用全笛卡尔集。
笛卡尔集产生的条件:
省略连接条件 连接条件无效如下示例:
如何避免笛卡尔集:
在 WHERE 加入有效的连接条件。
这时候就需要学习表关联的几种方式了。
根据连接方式的不同,Oracle的多表关联的类型分为:
内连接、外连接、自连接。
内连接分为:等值内连接、不等值内连接
外连接分为:左外连接、右外连接、全外连接
自连接是一种特殊的关联,可以包含内连接和外连接的连接方式。
Oracle是关系型数据库,它遵的规范(sql规范)。
但是,mysql和Oracle有些地方不一样,原因:各个厂商的实现可能会有差别。
Sql99 是为了 统一规范多个关系型数据库的通用语法的
Sql99的语法:
Oracle的语法:
sql语句 优化:
加上前缀:效率高!
等值内连接也称之为等值连接。
【示例】
-需求:查询一下员工信息,并且显示其部门名称
--需求:查询一下员工信息,并且显示其部门名称
SELECT * FROM emp t1,dept t2 WHERE t1.deptno=t2.deptno;--等值内连接,数据库的私有扩展语法:隐式内连接(mysql,oracle都支持)
SELECT * FROM emp t1 INNER JOIN dept t2 ON t1.deptno=t2.deptno;--sql99语法,显示内连接(所有符合sql99规范的都支持)
不等值内连接也称之为不等值连接。
【示例】需求:查询员工信息,要求显示员工的编号、姓名、月薪、工资级别。
--分析:要完成这个需求,需要使用到下面两张表:
--需求:查询员工信息,要求显示员工的编号、姓名、月薪、工资级别。
SELECT * FROM emp t1,salgrade t2 WHERE t1.sal >=t2.losal AND t1.sal<=t2.hisal;--隐式语法
SELECT * FROM emp INNER JOIN salgrade ON emp.sal >=salgrade.losal AND emp.sal <=salgrade.hisal --sql99
为什么要使用表的别名?
使用别名可以简化查询。 使用表名前缀可以提高执行效率。--SQL性能优化方案 在不同表中具有相同列名的列,可以用表的别名作为前缀来加以区分。
需要注意的是,如果一旦使用了表的别名,则不能再使用表的真名。
注意:这个理论。
分为左外连接,右外连接,全外连接(oracle特有 mysql
没有)。
--查询"所有"员工信息,要求显示员工号,姓名 ,和部门名称--要求使用左外连接
--查询"所有"员工信息,要求显示员工号,姓名 ,和部门名称--要求使用左外连接
SELECT * FROM emp t1 LEFT OUTER JOIN dept t2 ON t1.deptno=t2.deptno;--sql99标准语法
SELECT * FROM emp t1,dept t2 WHERE t1.deptno=t2.deptno(+);--oracle私有语法(mysql不支持),+放到右边是左外,你可以认为(+)是附加补充的意思。--要求查询所有的信息的表,我们可以称之为主表,而补充信息的表,称之为从表
----查询所有部门及其下属的员工的信息。--右外连接
SELECT * FROM emp t1 RIGHT OUTER JOIN dept t2 ON t1.deptno=t2.deptno;--sql99--右外连接--右边表(dept)数据全部显示。
SELECT * FROM emp t1,dept t2 WHEREt1.deptno(+)=t2.deptno;--oracle语法,右外连接
SELECT t1.*,t2.* FROM dept t1 ,emp t2 WHERE t1.deptno=t2.deptno(+);
--1.到底是使用左外还是右外,主要是看两张表的在语句中的位置,
--两张表是有主从关系,一般把主表放在左边,----一般两张表的情况下,我们都使用左连接.
--2.+到底是放在条件哪边?左外连接的+放在右边,右外连接的+放在左边.----记忆的方法:(+)放在从表的一方,起到数据附加的作用.
简单的说:左外连接就是左边的表的数据全部显示,右外就是右边的表的数据全部显示。
这种(+)的写法,只能用在Oracle。不能用于mysql!
一定要有主表和从表这个概念,分清那张是主表,哪张是从表。
把你想查询基础表当成左表。想把谁全部都查询出来就当成主表。
到底哪张是主表哪张是从表?最终还看你的需求。
一般我们把主表放在左边,使用左外连接。
一般情况下,我们就用左连接就行了。
左表和右表的数据全部都显示,而且不是笛卡尔集。
相当于左外+右外的数据。
【示例】
需求:要求将所有员工和所有部门都显示出来
--全外连接
SELECT * FROM emp t1 LEFT OUTER JOIN dept t2 on t1.deptno=t2.deptno
UNION
SELECT * FROM emp t1 RIGHT JOIN dept t2 ON t1.deptno=t2.deptno;
SELECT * FROM emp t1 FULL OUTER JOIN dept t2 ON t1.deptno=t2.deptno;--sql99语法,Oracle没有私有扩展的语法。而且,mysql没有全外
自连接,就是将一张表当成两张表来查询。
自连接的查询的原理:就是将一张表当成两张表来使用.
【示例】
1.查询员工信息,要求同时显示员工和员工的领导的姓名
2.查询"所有"员工信息,要求同时显示员工和员工的领导的姓名
--查询员工信息,要求同时显示员工和员工的领导的姓名
SELECT * FROM emp t1,emp t2 WHERE t1.mgr=t2.empno;
--查询"所有"员工信息,要求同时显示员工和员工的领导的姓名
SELECT * FROM emp t1,emp t2 WHERE t1.mgr=t2.empno(+);
自连接是一种特殊的多表连接方式,其实含有内连接和外连接的操作.
注意问题:你也要注意笛卡尔集的产生.
子查询也称之为嵌套子句查询。
语法上的运行使用规则:
子查询 (内查询、嵌套子句) 在主查询之前一次执行完成。(子查询先执行) 子查询的结果被主查询使用 (外查询)。 子查询要包含在括号内。 将 子查询放在比较条件的右侧。【需求】谁的工资比scott高?
采用连接的方式写(这里是自连接,见下图):
--【需求】谁的工资比scott高?
--多表关联查询:自连接的不等值连接
SELECT * FROM emp t1,emp t2 WHERE t2.ename='SCOTT' AND t1.sal>t2.sal
--不等值连接
采用子查询的方式写:
--子查询
--分析一下:谁的工资比scott高?--->1,scott工资是多少2,谁的工资比3000高
SELECT sal FROM emp WHERE ename='SCOTT';
SELECT * FROM emp WHERE sal >3000;
SELECT * FROM emp WHERE sal >(SELECT sal FROM emp WHERE ename='SCOTT');
对比可以发现:在某些业务上,子查询比连接查询更容易理解。
单行操作符(> = <)对应单行子查询,多行操作符(in,not in)对应多行子查询。
其中<>也可以可以用!=代替,意思一样。
【示例】--查询部门名称是SALES的员工信息
--查询部门名称是SALES的员工信息
SELECT * FROM emp WHERE deptno=(SELECT deptno FROM DEPT WHERE dname ='SALES')
了解:子查询可以是一张表的数据,也可以是不同表的数据。
【代码】
需求:查找工作和'Rose' 这个人的工作一样的员工信息
需求:查找工作和'Rose' 这个人的工作不一样的员工信息
--需求:查找工作和'Rose' 这个人的工作一样的员工信息
SELECT job FROM emp WHERE ename = 'Rose';
SELECT * FROM emp WHERE job =(SELECT job FROM emp WHERE ename = 'Rose');
SELECT * FROM emp;
--需求:查找工作和'Rose' 这个人的工作不一样的员工信息
SELECT * FROM emp WHERE job !=(SELECT job FROM emp WHERE ename = 'Rose');
--结论: 只要子查询返回的结果是null的话, 那么主查询的结果就一定是null
注意:使用子查询的时候,一定要保证子查询不能为空,否则数据就会出现异常。
【示例】需求:查找工作和'SMITH' 'ALLEN'这两个人的工作一样的员工信息
【示例】
需求:查找工作和'SMITH' 'ALLEN'这两个人的工作一样的员工信息
--需求:查找工作和'SMITH' 'ALLEN' 这两个人的工作不一样的员工信息
--需求:查找工作和'SMITH' 'ALLEN' 这两个人的工作一样的员工信息
SELECT JOB FROM emp WHERE ename IN('SMITH','ALLEN');
SELECT * FROM emp WHERE job IN(SELECT JOB FROM emp WHERE ename IN('SMITH','ALLEN'));
--需求:查找工作和'SMITH' 'ALLEN' 这两个人的工作不一样的员工信息
SELECT * FROM emp WHERE job NOT IN(SELECT JOB FROM emp WHERE ename IN('SMITH','ALLEN'));
【示例】需求:查询工资比30号部门任意一个员工的工资高的员工信息。--面试题
【示例】需求:查询工资比30号部门所有员工的工资高的员工信息。
--需求:查询工资比30号部门任意一个员工的工资高的员工信息。--面试题
SELECT * FROM emp WHERE deptno =30;
--任意一个:比最低的那个高就ok。
SELECT * FROM emp WHERE sal >(SELECT MIN(sal) FROM emp WHERE deptno=30);
--any(多行函数)
SELECT * FROM emp WHERE sal >ANY(SELECT sal FROM emp WHERE deptno=30);
--【示例】需求:查询工资比30号部门所有员工的工资高的员工信息。
SELECT * FROM emp WHERE sal>(SELECT MAX (sal) FROM emp WHERE deptno=30);
--all(多个返回记录)--max(sal)
SELECT * FROM emp WHERE sal>ALL(SELECT sal FROM emp WHERE deptno=30);
分析结果:
虚拟临时表是临时表的一种,是运行过程中,内存中虚拟出来的一张临时表,用于sql的操作。
【示例】
--虚拟表
SELECT * FROM
(
SELECT * FROM emp WHERE deptno=30 --虚表:将查询结果再作为一张表来使用。
) t
WHERE sal>2000
理论上,在都可以实现需求的情况下尽量选择多表查询。
原因:子查询会操作两次,多表查询只操作一次。多表的效率高。
但要注意的是,多表查询如果产生了笛卡尔集(语句上要注意条件的使用),则会出现严重的效率问题。
一般不在子查询中使用排序(order by),但在top-N分析问题中必须在子查询中使用排序。
最常用的两个伪列:rownum和rowid。
ROWNUM(行号):是在查询操作时由ORACLE为每一行记录自动生成的一个编号。
每一次查询ROWNUM都会重新生成。(查询的结果中Oracle给你增加的一个编号,根据结果来重新生成)
rownum永远按照默认的顺序生成。(不受orderby的影响)
rownum只能使用< <=,不能使用> >=符号,原因是:Oracle是基于行的数据库,行号永远是从1开始,即必须有第一行,才有第二行。
【示例】需求:查询出所有员工信息,并且显示默认的行号列信息。
--需求:查询出所有员工信息,并且显示默认的行号列信息。
SELECT ROWNUM,t.* FROM emp t;--* 和指定的列一起显示的时候,必须加别名
提示两点:
ROWNUM是由数据库自己产生的。 ROWNUM查询的时候自动产生的。
【示例】
--需求:查询出所有员工信息,按部门号正序排列,并且显示默认的行号列信息。
SELECT ROWNUM,t.* FROM emp t ORDER BY deptno;--order by 的原理:将查询结果(此时行号已经有了,已经和每一行数据绑定了)进行排序。
- --order by是查询语句出来的结果之后再排序的,,rownu是在查询出来结果的时候产生。order by不会影响到行号
--先排序,再查询
SELECT ROWNUM,t.* FROM
(
SELECT * FROM emp ORDER BY deptno
) t
结论:
order by排序,不会影响到rownum的顺序。rownum永远按照默认的顺序生成。
所谓的"默认的顺序",是指系统按照记录插入时的顺序(其实是rowid)。
回顾mysql如何排序?
select * from table limit m,n
其中m是指记录开始的index,从0开始,表示第一条记录
n是指从第m+1条开始,取n条。
select * from tablename limit 3,3
即取出第4条至第6条,3条记录
Oracle如何分页呢?
结论:Mysql使用limit的关键字可以实现分页,但Oracle没有该关键字,无法使用该方法进行分页。
【示例】需求:根据行号查询出第四条到第六条的员工信息。
--需求:根据行号查询出第四条到第六条的员工信息。
SELECT ROWNUM,t.* FROM emp t;
SELECT ROWNUM,t.* FROM emp t WHERE ROWNUM >=4 AND ROWNUM<=6;
--rownum只能使用< <=,不能使用> >=符号,原因是:Oracle是基于行的数据库,行号永远是从1开始,即必须有第一行,才有第二行。
SELECT ROWNUM,t.* FROM emp t WHERE ROWNUM<=6;
--方案:可以使用子查询
SELECT rownum,t2.* FROM
(
SELECT ROWNUM r,t.* FROM emp t WHERE ROWNUM<=6--此时子查询的rownum已经变成了虚表的一个列
) t2--尽量让虚表尽量小
WHERE t2.r >=4
--需求:要分页查询,每页3条记录,查询第二页
/*
pageNum=2
pageSize=3
计算:
firstIndex=pageSize*(pageNum-1);
maxCount=pageSize;
mysql:
limit 起始索引firstIndex,最大记录数maxCount
Oracle:
//起始行号
firstRownum=pageSize*(pageNum-1)+1
//结束行号
endRownum=firstRownum+pageSize-1
具体计算:
firstRownum=3*(2-1)+1=4;
endRownum=4+3-1=6;
*/
--写Oracle的分页,从子查询写起,也就是说从小于等于写起,或者说从endRownum写起
SELECT ROWNUM ,t2.* FROM
(
SELECT ROWNUM r,t.* FROM emp t WHERE ROWNUM <=6
) t2 WHERE t2.r >=4;
--优化
SELECT * FROM
(
SELECT ROWNUM r,t.* FROM emp t WHERE ROWNUM <=6
) WHERE r >=4;
SELECT empno,ename,job FROM--结果指定字段
(
SELECT ROWNUM r,t.* FROM emp t WHERE ROWNUM <=6
) WHERE r >=4;
--按照薪资的高低排序再分页
SELECT * FROM
(
SELECT ROWNUM r,t.* FROM emp t WHERE ROWNUM <=6 ORDER BY sal DESC
) WHERE r >=4 ;
SELECT * FROM emp ORDER BY sal DESC;
--先排序薪资,再分页
SELECT * FROM
(
SELECT ROWNUM r,t.* FROM
(SELECT * FROM emp ORDER BY sal DESC) t
WHERE ROWNUM <=6 ORDER BY sal DESC
)
WHERE r >=4 ;--Hibernate会自动将所有数据封装到实体对象(多余出来的行号那一列不会封装)
--如果不需要额外的字段,则只需要指定特定的列名就可以了。
--优化:子查询字段尽量少一些。数据量少。比如,表中有100个字段,但你就想显示5个,那么,你就子查询中直接指定5个就ok了。但,使用orm框架的建议都查出来。
SELECT * FROM
(
SELECT ROWNUM r,t.* FROM
(SELECT ename,job,sal FROM emp ORDER BY sal DESC) t
WHERE ROWNUM <=6 ORDER BY sal DESC
)
WHERE r >=4 ;
--通用
SELECT * FROM
(
SELECT ROWNUM r,t.* FROM
(SELECT ename,job,sal FROM emp ORDER BY sal DESC) t
WHERE ROWNUM <=endRownum ORDER BY sal DESC
)
WHERE r >=firstRownum ;
/*
另外一种计算方法(索引算法)
firstIndex=pageSize*(pageNum-1);
endRownum=firstIndex+pageSize;
*/
SELECT * FROM
(
SELECT ROWNUM r,t.* FROM
(SELECT ename,job,sal FROM emp ORDER BY sal DESC) t
WHERE ROWNUM <=endRownum ORDER BY sal DESC
)
WHERE r > firstIndex;--Hibernate的内置算法
2016-10-22
----需求:要分页查询,每页3条记录,查询第二页
/*
mysql: select * from emp limit 3,3;
page = 2;
pageSize = 3;
firstIndex = (page-1)*pageSize;
maxCount = pageSize;
select * from emp limit firstIndex,maxCount;
oracle:
page = 2;
pageSize = 3;
startRowNum = (page-1)*pageSize+1;
endRowNum = pageSize*page
select * from (select rownum r,t.* from emp t where rownum<=endRowNum) where r>=startRowNum;
----按照薪资的高低排序再分页
*/
SELECT *FROM emp ORDER BY sal DESC;
SELECT ROWNUM,t.* FROM(SELECT *FROM emp ORDER BY sal DESC) t WHERE ROWNUM<=6;
SELECT * FROM (SELECT ROWNUM r,t.* FROM(SELECT *FROM emp ORDER BY sal DESC) t WHERE ROWNUM<=6) t2 WHERE t2.r>=4;
分析原因:
rownum只能使用< <=,不能使用> >=符号,原因是:Oracle是基于行的数据库,行号永远是从1开始,即必须有第一行,才有第二行。
【提示】:
如何记忆编写Oracle的分页?建议写的时候从里到外来写,即先写小于的条件的子查询(过滤掉rownum大于指定值的数据),再写大于的条件的查询(过滤掉rownum小于的值)。 Oracle的分页中如果需要排序显示,要 先排序操作,再分页操作。(再嵌套一个子查询) 性能优化方面:建议在最里层的子查询中就直接指定字段或者其他的条件,减少数据的处理量。
ROWID(记录编号):是表的伪列,是用来唯一标识表中的一条记录,并且间接给出了表行的物理位置,定位表行最快的方式。
主键:标识唯一的一条业务数据的标识。主键是给业务给用户用的。不是给数据库用的。 记录编号rowid:标识唯一的一条数据的。主要是给数据库用的。类似UUID。
【示例】
SELECT t.*,ROWID FROM emp t;
使用insert语句插入数据时,oracle会自动生成rowid并将其值与表数据一起存放到表行中。
这与rownum有很大不同,rownum不是表中原本的数据,只是在查询的时候才生成的。
提示:rownum默认的排序就是根据rowid
这里列举两个常见的应用:
去除重复数据。--面试题—了解 在plsql Developer中,加上rowid可以更改数据。
关于主键和rowid的区别:
相同点:为了标识唯一一条记录的。
不同点:
主键:针对业务数据,用来标识不同的一条业务数据。
rowid:针对具体数据的,用来标识不同的唯一的一条数据,跟业务无关。
【示例】需求:删除表中的重复数据,要求保留重复记录中最早插入的那条。(DBA面试题)
--查看rowid
SELECT t.*,ROWID FROM emp t;
--需求:删除表中的重复数据,要求保留重复记录中最早插入的那条。(DBA面试题)
--准备测试表和测试数据:
--参考建表语句如下:
-- Create table
create table test
(
id number,
name varchar2(50)
)
;
--插入测试数据
INSERT INTO TEST VALUES(1,'xiaoming');
INSERT INTO TEST VALUES(2,'xiaoming');
INSERT INTO TEST VALUES(3,'xiaoming');
COMMIT;
SELECT * FROM TEST ;
--通过rowid,剔除重复xiaoming,保留最早插入的xiaoming
SELECT t.*,ROWID FROM TEST t;
--删除的的时候,可以先查询你要删除的东东
SELECT t.*,ROWID FROM TEST t WHERE ROWID > (SELECT MIN(ROWID) FROM TEST);
DELETE FROM TEST t WHERE ROWID > (SELECT MIN(ROWID) FROM TEST);
--语句有缺点:条件不足,会只保留一条数据,误删其他数据
--重新插入测试数据
INSERT INTO TEST VALUES(1,'xiaoming');
INSERT INTO TEST VALUES(2,'xiaoming');
INSERT INTO TEST VALUES(3,'xiaoming');
INSERT INTO TEST VALUES(4,'Rose');
INSERT INTO TEST VALUES(5,'Rose');
COMMIT;
--剔除重复数据
SELECT * FROM TEST WHERE ROWID NOT in(SELECT MIN(ROWID) FROM TEST GROUP BY NAME);
DELETE TEST WHERE ROWID NOT in(SELECT MIN(ROWID) FROM TEST GROUP BY NAME);
注意:删除重复记录一定要小心,万一你的条件有问题,就会删错数据.建议删除之前,可以先用查询查一下,看是否是目标数据。
数据一旦删除恢复比较麻烦,但可以恢复,采用日志回滚。一般不要轻易用。
说完了所有的查询,下面说说增、删、改。
通过工具修改数据
提示:是否能使用工具修改,主要看语句有没有rowid。
语法:
INSERT INTO table VALUES--单条插入语法
INSERT INTO table SELECT查询语句--批量插入语法(主要用于将一张表中的数据批量插入到另外一张表中)
【示例】需求:将dept表中部门名称不为空的数据都插入到test表中
--需求:将dept表中部门"名称"不为空的数据都插入到test表中
INSERT INTO TEST(ID,NAME) SELECT deptno,dname FROM dept;--select的结果必须能插入到目标表中。(字段个数要对应、字段类型要对应)
INSERT INTO TEST SELECT deptno,dname FROM dept ;--必须前后字段对应
--非法使用批量插入
INSERT INTO TEST SELECT deptno,dname,loc FROM dept ;
友情提示:面试经常会被问道。
高水位线英文全称为high water mark,简称HWM,那什么是高水位呢?
在Oracle数据的存储中,可以把存储空间想象为一个水库,数据想象为水库中的水。水库中的水的位置有一条线叫做水位线,在Oracle中,这条线被称为高水位线(High-warter mark, HWM)。在数据库表刚建立的时候,由于没有任何数据,所以这个时候水位线是空的,也就是说HWM为最低值。当插入了数据以后,高水位线就会上涨,但是这里也有一个特性,就是如果你采用delete语句删除数据的话,数据虽然被删除了,但是高水位线却没有降低,还是你刚才删除数据以前那么高的水位。也就是说,这条高水位线在日常的增删操作中只会上涨,不会下跌。
【高水位对Oracle的应用有什么影响呢?】
高水位对查询有巨大的影响。而且还浪费空间。
【解读Oracle中Select语句的特性】
极端例子:数据库有10w条数据,删掉了前面的99999个,我select查询的时候,还是需要扫描10w次,虽然表中只有一条数据。效率还是非常的低!!!!!
如何解决高水位带来的查询效率问题呢?
将表数据备份出来,摧毁表再重建(truncate table),然后再将数据导回来。 收缩表,整理碎片,可使用变更表的语句:alter table 表名 move
【示例】查看、测试、消除高水位—了解
--之前查看rowid
SELECT t.*,ROWID FROM TEST t;
--对表进行分析,收集统计信息(执行了收集信息的动作,user_tables表的块字段才有数据)
analyze table TEST compute statistics;
--查询表数据的块信息,其中blocks是高水位,empty_blocks是预申请的块空间。
select table_name,blocks,empty_blocks from user_tables where table_name='TEST';
--收缩表(整理碎片),降低高水位,消除行移植和行链接,不释放申请的空间
ALTER TABLE TEST MOVE;
--对表进行分析,收集统计信息(执行了收集信息的动作,user_tables表的块字段才有数据)
analyze table TEST compute statistics;
--查询表数据的块信息,其中blocks是高水位,empty_blocks是预申请的块空间。
select table_name,blocks,empty_blocks from user_tables where table_name='TEST';
--之后查看rowid
SELECT t.*,ROWID FROM TEST t;
结论:
收缩表之后,高水位线下降了。 收缩表之后,rowid发生了变化。
注意:
move最好是在空闲时做,记得move的是会产生锁的(如果你move的时候需要很长事件,那么别人是不能操作这张表的。排他锁) move以后记得 重建index(后续讲到索引,你会知道索引存放的其实就是数据的地址信息。当数据的地址变动了, 索引也会失效。)语法:ALTER INDEX 索引名字 REBUILD;
事务是保持数据的一致性,它由相关的DDL或者DML语句做为载体,这组语句执行的结果要么一起成功,要么一起失败。
SQL92标准定义了数据库事务的四个特点(ACID):
原子性 (Atomicity) :一个事务里面所有包含的SQL语句是一个执行整体,不可分割,要么都做,要么都不做
一致性 (Consistency) :事务开始时,数据库中的数据是一致的,事务结束时,数据库的数据也应该是一致的
隔离性 (Isolation): 多个事务并发的独立运行,而不能互相干扰,一个事务修改,新增,删除数据在根据当前事务的事务隔离级别基础上,其余事务能看到相应的结果(这里为什么这么说,下面我会给我具体的例子进行分析)
持久性 (Durability) : 事务被提交后,数据会被永久保存
Oracle的默认事务开启和结束是跟mysql不一样的。
回顾:mysql的事务是如何开启的?
MySQL默认采用autocommit模式运行。这意味着,当您执行一个用于更新(修改)表的语句之后,MySQL立刻把更新存储到磁盘中,不需要手动提交。
如果需要手动管理事务,需要显式的关闭自动事务:Set autocommit false,然后显式的手动开启事务:START TRANSACTION,直到手动COMMIT或ROLLBACK结束事务为止。
那么,Oracle的事务是如何开启的?
Oracle的事务默认是手动管理事务,事务是自动开启(不需要显式的开启,隐式开启),但一般需要手动提交关闭。
Oracle事务的开始和结束的触发条件:
事务的开始:以第一个DML语句(insert update delete)的执行作为开始,即是自动开启的事务。 事务的结束(以下条件之一): 显式结束:commit, rollback(还是隐式commit) 隐式结束(自动提交):DDL(create table…)和DCL(所以不能回滚 ),exit(事务正常退出) 隐式回滚(系统异常终止):关闭窗口,死机,掉电。
工具上的事务按钮:
隐式提交:
提示:一般情况下,我们尽量使用手动提交事务。
事务过程中是可以控制的,通过SAVEPOINT语句。
SAVEPOINT的作用:
使用 SAVEPOINT 语句在当前事务中创建保存点,语法:SAVEPOINT 保留点名称。 使用 ROLLBACK 语句回滚到创建的保存点。 语法:ROLLBACK TO 保留点名称。
【示例演示】
SELECT * FROM TEST;
INSERT INTO TEST VALUES(85,NULL);
SELECT * FROM TEST;
SAVEPOINT aa;--保留点
INSERT INTO TEST VALUES(86,NULL);--后悔了,不插入了
SELECT * FROM TEST;
--回滚
ROLLBACK TO aa;
SELECT * FROM TEST;
INSERT INTO TEST VALUES(87,NULL);
SELECT * FROM TEST;
--提交
COMMIT;
SELECT * FROM TEST;
注:
当前事务提交后,事务中所有的保存点将被释放。
JAVA中也有关于保留点的API,
具体调用采用Connection对象来操作它,相关方法如下:
数据库对象,是数据库的组成部分,有表(Table )、索引(Index)、视图(View)、用户(User)、触发器(Trigger)、存储过程(Stored Procedure)、图表(Diagram)、缺省值(Default)、规则(Rule)等。
表名和列名的基本规范如下:
【扩展】
另外,每个公司都有自己特有的命名规范,比如,要求所有的数据库对象都要加上一个前缀,用于快速识别对象的类别。
比如表的命名:
t_person :存放个人信息的表。
t_crm_person:存放客服子系统模块的人员信息表。
视图的命名:
v_person:用来查询人员信息的视图。
命名规范的作用:
良好的命名规范便于识别和管理,对于系统开发和维护都有很大的帮助。 使用工具的提示功能也更容易快速定位到所需要的对象。
创建表的要求条件:
必须具备CREATE TABLE权限、存储空间。 必须指定表名、列名、数据类型、数据类型的大小
语法:
Create table 新表 as select from 旧表 条件(如果条件不成立,则只复制结构,如果条件成立,复制结构和值)
使用子查询创建表,而且还可以将创建表和插入数据结合起来。
【示例】
--复制一张和原来一模一样的新表,包含数据
--复制一张和原来一模一样的新表,包含数据
CREATE TABLE t_dept AS SELECT * FROM dept;
SELECT * FROM t_dept
--复制一张和原来一模一样的新表,不要数据,只要结构
CREATE TABLE t_dept_empty AS SELECT * FROM dept WHERE 1<>1;
SELECT * FROM t_dept_empty;
---t_dept,在现网(正式环境)确实要测试一下数据.一般我们可以在建立一张和这个一模一样的表.c
--能不能只复制部分字段建立新表?可以!
--复制表的部分字段
CREATE TABLE t_dept_part AS SELECT deptno,dname FROM dept;
SELECT * FROM t_dept_part;
提示:
复制表有没有数据的区别,是select子句结果有没有数据。如果子句结果没有数据,则仅创建表,如果有数据,则创建表的同时也插入符合条件的数据。
注意:
指定的列和子查询中的列要一一对应 通过列名和默认值定义列关于where 1=1的写法,一般我们用来拼凑条件的。
1<>1是为了营造一个永远不成立的条件。
修改表的列:
修改表的列的能力:
追加新的列 修改现有的列 删除一个列
修改对象的名称:
作用:
执行RENAME语句改变表, 视图, 序列, 或同义词的名称。 要求必须是对象的拥有者【示例】
RENAME t_dept TO t_dept_new;
Table renamed.
操作方式:
注意:
数据和结构都被删除。 所有正在运行的相关事物被提交。(ddl语句) 所有相关索引被删除。(表附属对象会被删除) DROP TABLE 语句不能回滚,但是可以 闪回。
完整的oracle数据库的版本的情况下,普通用户删除的表,会自动放入回收站
你可以从回收站还原(闪回)。
友情提示:
日常操作中,删除操作一定要小心,一旦删除了且没有放入回收站,则意味着数据的丢失!
记住一句话:数据无价!!!
数据库的约束可以认为是对表的数据的一种规则。
其中:check约束是Oracle特有的约束。
通过工具快速得到SQL的代码:
插入数据测试Check约束
在应用开发中,主键约束一般要设置,其他如非空、唯一、默认值、检查等约束,可以根据实际情况来添加。而外键约束是否要设置,是存在一点争议的。(争议在性能上)
一般建议:
在大型系统中(性能要求不高,安全要求高),可以使用外键;在大型系统中(性能要求高,安全自己控制),不用外键;小系统随便。 不用外键的话,可以用 程序控制数据一致性和完整性,可以在代码的数据层通过代码来保证一致性和完整性。 用外键要适当,不能过分追求。
从JAVA开发的角度上说,一般不建议使用外键,除了性能外,使用程序控制业务更灵活。
比如客户和订单,这两个之间的关联虽然可以建立外键关系,实现级联效果(如级联删除)。
如果有外键约束,则删除客户的时候,必须先删除客户下的订单,否则,不允许删除。 从数据完整一致性的角度上说,如果客户被删除了,订单也无意义了,这是合理的。 但从业务角度上说,客户被删除了,是否意味这订单也必须删除呢?单纯保留订单的行为也是合理的。
需求:
Mysql中主键有自增长的特性.
Oracle中,主键没有自增长这个特性.那么如何解决这个问题.使用序列可以解决.
序列:可供多个用户来产生唯一数值的数据库对象
. 自动提供唯一的数值
. 共享对象
. 主要用于提供主键值
. 将序列值装入内存可以提高访问效率
这个是Oracle特色的。Mysql是没有的。
简单的说,他可以用来高效的生成主键值。
将序列提前装入内存,可以提高效率。
【示例】
创建一个简单的序列
CREATE SEQUENCE seq_test;
在ORACLE中为序列提供了两个伪列:
NEXTVAL 获取序列对象的下一个值(指针向前移动一个,并且获取到当前的值。) CURRVAL 获取序列对象当前的值
【示例】
为什么?
原因是:序列初始化之后指针在第一个数之前。必须先向前移动才可以查询的到。
数组的指针默认在1之前,并没有指向第一个值,要想使用必须向前移动一下。(指针只能向前不能向后)
[1,2,3….20][
*
操作指针:
[1,2,3….20][
*
SELECT seq_test.nextval FROM dual;
移动一位并且取值。
Oracle建表的时候是否能像mysql那样设定一个自增长的列吗?
不行!
那如何解决呢?使用序列!
【示例】在插入数据的时候插入序列主键.
--在插入数据的时候插入序列主键.
INSERT INTO TEST VALUES(seq_test.nextval,'Jack');
问题:为什么这个值不是从1开始?
原因: 共享对象 序列是个独立对象.谁都能用,谁都能共享它.
2,当插入记录时报错,序列对象值也被使用,下一次再使用时,序列的值就会+1
【示例】序列的裂缝
INSERT INTO T_TESTSEQ VALUES(seq_test.nextval,'张三1');
ROLLBACK;
INSERT INTO T_TESTSEQ VALUES(seq_test.nextval,'张三2');
COMMIT;
SELECT * FROM T_TESTSEQ;
也就是说,用序列插入数据库的值不一定是连续的。
补充:
Mysql的自增长列也可以是不连续的.
序列出现裂缝的条件:
事务回滚。 系统异常。 多个表同时使用同一个序列。
这个序列是公用的对象。如果你很在意的话,就一个表用一个序列,但大多数情况下,这个主键值(代理主键)没有什么意义的话,可以多个表公用一个序列。
Oracle 服务器软件部分由两大部分组成, Oracle 数据库 和 Oracle 实例。
两者的解释如下:
Oracle 数据库(物理概念): 位于硬盘上实际存放 数据的文件和相应的程序文件, 这些文件组织在一起, 成为一个逻辑整体, 即为 Oracle 数据库. 因此在 Oracle 看来, "数据库" 是指硬盘上文件的逻辑集合, 必须要与内存里实例合作, 才能对外提供数据管理服务。 Oracle 实例(逻辑概念): 位于物理 内存里的数据结构. 它由一个 共享的内存池和多个后台进程所组成, 共享的内存池可以被所有进程访问. 用户如果 要存取数据库(也就是硬盘上的文件) 里的数据, 必须通过实例才能实现, 不能直接读取硬盘上的文件。实例的唯一标识也称之为SID(OSID)。
一个实例只能对应一个数据库,一个数据库可以有多个实例(RAC集群),但大多数情况下, 一个数据库上只有一个实例对其进行操作。我们就是通过连接到实例来操作数据库的。
常见的存储文件主要为三类:
数据文件。存储数据用的。例:表
控制文件。记录数据文件存放的位置。例:数据库名称、数据文件名称及位置。 日志文件。记录数据信息变化的。例:因故障问题造成一些数据没有及时写入到数据文件,可以使用日志文件恢复( Oracle日志回滚:如果你的数据被delete掉并且提交了,数据还是可以恢复的,可以通过日志来恢复的)。
ORACLE是属于文件存储。ORACLE中的数据是存放在一个个数据文件中,数据文件存放在磁盘中。
如果说数据文件是物理概念,那么表空间就是逻辑概念,Oracle通过表空间来对数据文件中的数据进行CRUD。
表空间是一种逻辑结构,是Oracle最大的逻辑单元,可以理解为:所有的数据都存储在表空间中。
表空间的属性特点:
一个数据库可以包含多个表空间,一个表空间只能属于一个数据库。 一个表空间可以由一个或多个数据文件组成,一个数据文件只能属于一个表空间。 表空间可以划分成更细的逻辑存储单元。(了解)
官方数据存储结构图:
各对象之间的存储对应关系图:
所有的数据库对象都存储在表空间中,而表空间被数据库服务管理。 一个表空间可以对应N个数据文件,表空间是逻辑概念,而数据文件是物理概念。 方案(SCHEMA模式)是表、视图、索引等数据库对象的逻辑集合,它通过数据库服务来间接管理这些对象。 一个用户(user)创建时会同时创建一个同名的方案(schema),即,你甚至可以认为用户和方案是同一个东西(事实上不是,用户主要是做权限等相关管理的)。当用户登录后,就立刻拥有了该同名方案下所有对象。 方案(用户)和表空间没有什么必然关系,一个方案拥有一个默认的表空间,但同时可以使用多个表空间来存储它的对象。一个表空间可以为不同的方案来存储其所属对象
【补充阅读】下面有个很形象的比喻,是从网上摘的,不妨一看:
我们可以把database看做是一个大仓库,仓库分了很多很多的房间,schema就是其中的房间,一个schema代表一个房间,table可以看做是每个schema中的床,table被放入每个房间中,不能放置在房间之外,那岂不是晚上睡觉无家可归了,然后床上可以放置很多物品,就好比table上可以放置很多列和行一样,数据库中存储数据的基本单元是table,显示中每个仓库放置物品的基本单位就是床,user就是每个schema的主人,(所以schema包含的是object,而不是user),user和schema是一一对应的,每个user在没有特别指定下只能使用自己schema的东西,如果一个user想使用其他schema的东西,那就要看那个schema的user有没有给你这个权限了,或者看这个仓库的老大(DBA)有没有给你这个权限了。换句话说,如果你是某个仓库的主人,那么这个仓库的使用权和仓库中的所有东西都是你的,你有完全的操作权,可以扔掉不用东西从每个房间,也可以防止一些有用的东西到某个房间,你还可以给每个user分配具体的权限,也就是他到某一个房间能做些什么,是只能看(read-only),还是可以像主人一样有所有控制权(R/W),这个就要看这个user所对应的角色Role了。
作业: 课后了解 用户和方案的关系
数据操作的过程:
【小结】
表空间:属于一种逻辑结构。记录物理文件的逻辑单位。是Oracle最大的逻辑单位.
也就是说,我们所有的数据都存储在表空间中.
临时表空间和UNDO表空间的异同:(了解)
相同之处:两者都不会永久保存数据。 不同之处:UNDO表空间用于存放UNDO数据,当执行DML操作时,oracle会将这些操作的旧数据写入到UNDO段,以保证可以回滚和事务隔离读取等,主要用于数据的修改等;而临时表空间主要用来做查询和存放一些缓冲区数据。字典管理:全库所有的空间分配都放在数据字典中。容易引起字典争用,而导致性能问题。
本地管理:空间分配不放在数据字典,而在每个数据文件头部的第3到第8个块的位图块,来管理空间分配。oracle公司推荐使用本地管理表空间。
注:表空间的创建一般是由DBA来操作完成的,而且需要管理员权限(我们一般用sys)。
三种表空间中,UNDO表空间通常是由Oracle自动化管理的,而另外两种表空间则一般需要手动创建。
【常用参数语法】:
--创建永久数据表空间
CREATE TABLESPACE TABLESPACE_NAME
[DATAFILE DATAFILE1,[DATAFILE 2]…]
[LOGGING | NOLOGGING]
[ONLINE|OFFLINE]
[EXTENT_MANAGEMENT_CLAUSE]
参数说明:
TABLESPACE_NAME,表空间名称随意,但最好遵循一定的规范,如tbl_itcast18_dat、tbl_itcast18_tmp等。 DATAFILE,表空间的类型 DATAFILE1 数据文件需要有如下格式:文件名 SIZE 初始文件大小 [AUTOEXTEND OFF| ON] [MAXSIZE|NEXT SIZE MAXSIZE SIZE] 文件名是数据文件的路径名,可以是绝对路径,也可以是相对路径,如"路径\xxx.dbf",注意路径必须先建立好。 初始化文件大小,是数据文件刚建立起来的时候所占物理磁盘空间的大小; AUTOEXTEND,是否自动扩展数据文件的大小,OFF表示关闭自动扩展,数据文件只能是初始大小,ON表示开启自动扩展,当数据文件超过初始大小的时候,会自动增大。默认值为OFF。 如果设置自动扩展,则需要设置最大值MAXSIZE,如设置2000m,当然也可以设置为UNLIMITED,表示无限表空间。如果要指定每次扩展的大小,可以使用NEXT SIZE MAXSIZE SIZE语法,表示每次扩展多少尺寸,最大能扩展到多大(大小上限)。 [LOGGING | NOLOGGING]该子句用来声明这个表空间上所有的用户对象的日志属性,即当操作包括表,索引,分区,物化视图,物化视图上的索引,分区等是否记录日志。缺省值为LOGGING。 [ONLINE|OFFLINE]表空间的状态,ONLINE表示表空间创建后立即有效,OFFLINE表示表空间创建后暂时无效,即不能使用,只有设置为ONLINE后才有效,默认值为ONLINE。 EXTENT_MANAGEMENT_CLAUSE表空间如何管理范围,推荐设置为本地管理,值为EXTENT MANAGEMENT LOCAL,如果不指定该值,则ORACLE会根据初始化时内部的其他参数进行自动设置一个默认值,生产环境下建议指定该值为本地管理。
--创建临时数据表空间
CREATE TEMPORARY TABLESPACE TABLESPACE_NAME
TEMPFILE DATAFILE1,[DATAFILE 2]…
EXTENT_MANAGEMENT_CLAUSE
参数说明:
DATAFILE1数据文件的格式语法:文件名 SIZE 初始文件大小,注意临时数据表空间的数据文件一般不需要指定最大值,Oracle对其采用了贪吃算法策略,因此,该表空间会自动逐渐增大。当然你也可以手动指定。 其他参数见永久数据表空间的。 临时表空间默认是不记日志的。【最简语法】
Create tablespace 表空间名称
表空间类型
'物理文件全路径'
Size 初始文件大小
【示例】
永久数据表空间和临时数据表空间的建立。
--建立一个数据表空间。
CREATE TABLESPACE tbl_itcast_dat
DATAFILE
'D:\Applications\Oracle\mydata\itcast_dat01.dbf'
SIZE 50m
AUTOEXTEND ON
NEXT 5m
MAXSIZE 2000m
EXTENT MANAGEMENT LOCAL
--创建临时数据表空间。
CREATE TEMPORARY TABLESPACE tbl_itcast_tmp
TEMPFILE
'D:\Applications\Oracle\mydata\itcast__tmp.dbf'
SIZE 20m
EXTENT MANAGEMENT LOCAL
解释:
【提示】:
文件路径(data目录)必须提前存在,否则:
注意:
实际企业开发中,不要用最简化的方式来进行表空间的创建。
【参考示例1】
--创建数据表空间
CREATE TABLESPACE TBS_CSP_BS_DAT
DATAFILE '/dev/rlv_dat001' SIZE 2000M REUSE AUTOEXTEND OFF,
LOGGING
ONLINE
PERMANENT
EXTENT MANAGEMENT LOCAL;
--创建临时数据表空间
CREATE TEMPORARY TABLESPACE TBS_CSP_BS_TMP
TEMPFILE '/dev/rlv_dat009' SIZE 2000M REUSE AUTOEXTEND OFF
EXTENT MANAGEMENT LOCAL UNIFORM SIZE 10M;
注:
PERMANENT是显式的指定创建的是永久的表空间,用来存放永久对象。默认值。
【参考示例2】
--创建数据表空间
create tablespace tbs_user_data
logging
datafile 'D:\oracle\oradata\Oracle9i\user_data.dbf'
size 50m
autoextend on
next 50m maxsize 20480m
extent management local;
--创建临时数据表空间
create temporary tbs_user_temp
tempfile 'D:\oracle\oradata\Oracle9i\user_temp.dbf'
size 50m
autoextend on
next 50m maxsize 20480m
extent management local;
语法:
DROP TABLESPACE
【示例】
--删除表空间以及下面所有数据和数据文件(全删,寸草不生)
DROP TABLESPACE tbl_itcast_tmp INCLUDING CONTENTS AND DATAFILES;
提示:如果不加后面的一堆,则,只是将表空间进行了逻辑删除(Oracle无法管理使用这个表空间了,但数据文件还存在)。
【示例】
建立表的时候指定表空间。
企业开发中,一定不要用默认的表空间,一定使用要指定表空间。
最简的一个建表脚本:
注意:
写建表的语句的时候,可以指定存储的表空间,但不建议指定表空间的参数。
预备知识:
Oracle预定义有很多用户,用于不同的用途。这些用户大都默认是禁用的(如scott,hr等),但有两个最重要的用户是默认开启的,这两个用户就是SYS和SYSTEM。
SYS 帐户(数据库拥有者): 拥有 DBA 角色权限 拥有 ADMIN OPTION 的所有权限 拥有 startup, shutdown, 以及若干维护命令 拥有数据字典 SYSTEM 帐户 拥有 DBA 角色权限.
注意:这些帐户通常不用于常规操作。
Sys和system账户的区别:
sys用户是数据库的拥有者,是 系统内置的、权限最大的超级管理员帐号。 system用户只是拥有 DBA角色权限的一个管理员帐号,其实它还是归属于普通用户。
create user 用户名
identified by 密码(不要加引号)
default tablespace 默认表空间名 quota 5M on 默认表空间名
[temporary tablespace 临时表空间名]
[profile 配置文件名] //配置文件
[default role 角色名] //默认角色
[password expire] //密码失效
//如果设置失效,那么第一次登录的时候,会提醒你更改密码。
[account lock] //账号锁定(停用)
修改用户alter user 用户名 identified by 密码 quota 10M on 表空间名
alter user 用户名 account lock/unlock
删除用户drop user 用户名 [cascade].如果要删除的用户中有模式对象,必须使用cascade.
【示例】最简方式创建一个用户
切换到sys用户下:
注:未指定的参数都采用默认值。
【示例】借助工具创建一个用户
创建用户的时候指定的表空间,会成为以后在该用户下建立对象(表)的默认存储表空间。
-- 语句:Create the user
/*创建用户并指定表空间 */
create user itcast19
identified by itcast19
default tablespace TBL_ITCAST19_DAT
temporary tablespace TBL_ITCAST19_TMP; --上锁解锁改密码等
注意:
一般企业开发中,建表要手动指定表空间,可以让不同模块、不同功能的对象存储在不同的数据文件中,可以提高性能。
【示例】删除用户
--删除用户及其下面所有的对象
drop user itcasttest cascade;
提示,每个数据库用户帐户具备:
一个唯一的用户名 一个验证方法 一个默认的表空间 一个临时表空间 权限和角色 每个表空间的配额.
使用上面创建的用户登录测试:
结果报错。
提示说:该用户没有创建会话的权限,登录被拒绝。
那该如何赋权呢?赋什么权限呢?
Oracle内置有大量的权限属性:
常见权限:
我们可以将create session权限赋权给新建的用户.新建的用户就可以登录了.
我们再建立一张表看看:
结果又提示是权限不足。= =...
再添加建表的权限:
再次测试建表:
再添加一条数据看看:
竟然又没有权限!
。。。
结论:这样一个个添加权限非常的麻烦!
是否可以使用比较简单的方式将普通用户的权限赋予给一个用户呢?
可以!通过预定义内置角色就可以实现。
需要分配 unlimited tablespaces 权限
如何选择预定义的角色呢?
普通用户就选择:connect和Resource角色即可。
管理员用户选择:connect和Resource、dba角色。
/*给用户授予权限 */
grant connect,resource to username;
再次登录、各种操作测试,均正常了!
【提示】
如果遇到这个错误:
说明当前用户没有操作该表空间的权限,需要手动加入这个权限:
梳理回顾建立一个普通用户的过程:
1.创建用户—2.赋权限(connect和resourece角色)
几个概念:
方案就是属于某一用户的所有对象(表、视图等)的集合. 用户名和方案名往往是通用的. 一个用户只能关联一个方案. 创建用户时系统会自动创建一个同名方案(schema)
提示:
Scott用户的方案名也是scott,因此,后面我们将这两个概念放在一起用,即我们可以说,某表是scott用户下的对象,也可以说是scott方案下的对象。
跨域访问也称之为跨用户访问、跨方案访问,访问的方式为:用户名.对象名,
如在itcast用户下访问scott用户下的emp表的数据:
Select * from scott.emp;
原因:没有对象访问权限。
Oracle用户的权限分为两种:
系统权限(System Privilege): 允许用户执行对于数据库的特定行为,例如:创建表、创建用户等 对象权限(Object Privilege): 允许用户访问和操作一个特定的对象,例如: 对其他方案下的表的查询
【示例】需求:itcast用户要读取scott用户中emp表的数据。
--scott用户登录赋权:
--Sql语句:
--itcast用户登录测试:
注意:
赋权的时候,只能是自己拥有的权限、或者该权限是可以传递的,才可以将其赋予别人。
问题:
Itcast用户现在只需要查询10部门的员工数据就行了,scott也不想将所有数据都开放给itcast用户。
概念:
视图是一种 虚表. 视图 建立在已有表的基础上, 视图赖已建立的这些表称为 基表。 向视图提供数据内容的语句为 SELECT 语句, 可以将视图理解为 存储起来的 SELECT 语句. 视图向用户提供基表数据的另一种表现形式作用:
语法: create VIEW 视图名称 as select ….
提示:
子查询可以是任意复杂的 SELECT 语句。
语法详细分析:
纠正:默认值不是只读。
视图只能创建、替换和删除,不能修改。
【示例】创建10号部门的视图
--sql语句建立视图
CREATE VIEW v_emp10
AS
SELECT * FROM emp WHERE deptno=10
;
提示:如果提示权限不足而导致无法添加视图,则需要添加权限,一般为学习方便,我们会直接添加dba角色权限。
--切换到sys用户下,为scott添加dba权限:
【示例】查询视图
【示例】视图的真实内容查看
结论:
可以看出,视图的本质就是sql语句。
视图没有修改功能。
【示例】要将视图改为可以查询10号部门的员工信息且工资要大于2000:
CREATE OR REPLACE VIEW v_emp10
AS
SELECT * FROM emp WHERE deptno=10 AND sal >2000;
提示:
平时我们在编写建立视图的语句时候,一般直接把replace加上,即直接CREATE OR REPLACE。
【示例】删除10好部门的这个视图
DROP VIEW v_emp10;
SELECT * FROM v_emp10;
--先创建视图再创建表:一般用的不多,一般我们都是先有表再创建视图。
CREATE OR REPLACE FORCE VIEW v_test2015
AS
SELECT * FROM test2015;
SELECT * FROM v_test2015
--视图默认情况下和表一样,拥有表类似的功能,可以crud
SELECT t.*,ROWID FROM v_emp10 t;
SELECT * FROM emp;
CREATE OR REPLACE VIEW v_emp10
AS
SELECT * FROM emp WHERE deptno=10
WITH CHECK OPTION;--数据的增加和修改,必须满足子查询的条件
--一般视图,我们主要用来查询的,一般不维护它。
CREATE OR REPLACE VIEW v_emp10
AS
SELECT * FROM emp WHERE deptno=10
WITH READ ONLY;
一般情况下,视图主要用来提供查询的,并不希望用户去修改它,因此,我们可以创建只读视图。创建只读视图只需要添加with read only 选项即可,这样就可以屏蔽对视图的DML操作。
【示例】将已有的视图修改为只读视图
CREATE OR REPLACE VIEW v_emp_dept10
AS
SELECT * FROM emp WHERE deptno=10 AND sal >2000
WITH READ ONLY ;
友情提示:
其实,很多大的系统中,比如银行,某些客户会告诉你,这个表存这个数据,那个表存哪个数据,但实际上,可能不是真正的表,而是视图,而且还是只读的。
为什么给视图?原因是:
如果是存钱的表,那么放开给你,是不是非常危险。如果业务需要确实是需要更改这个表的数据呢?一般来调用存储过程(一般有提供,有一定特定功能,还能记录日志)来改表,为了安全!不能直接改表。
【示例】只放开scott下的emp表的部分数据给itcast14用户查询,开放的数据要求为:20号部门的员工,字段只显示员工号和姓名,且要求这两个字段的标题显示为中文。(要求本例使用工具来操作)
--在scott下创建视图(视图名称参考为:v_emp_dept20)
--将生成的脚本如下:
create or replace view v_emp_dept20 as
select empno "编号",ename "姓名"
from emp
where deptno=20
WITH READ ONLY;
--scott下查询验证一下:
SELECT * FROM v_emp_dept20;
--将该视图赋予itcast用户:在scott用户下操作:
grant select on v_emp_dept20 to itcast;
--切换到itcast用户下进行查询验证:
Select * from scott.v_emp_dept20;
另外补充:
视图可以屏蔽筛选不同字段、字段名称等,因此,你看到的时候的字段也未必是真实表中存在的!
CREATE OR REPLACE VIEW v_emp10
AS
SELECT empno 编号,ename empname FROM emp WHERE deptno=10
WITH READ ONLY;
视图和表的区别:
视图是实体表的映射,视图和实体表区别就是于视图中没有真实的数据存在。
什么时候使用视图:
在开发中,有一些 表结构是不希望过多的人去接触,就把实体表映射为一个视图。 在项目过程中,程序人员主要关注编码的性能、业务分析这方面。 对于一些复杂的SQL语句,设计人员会提前把这些语句封装到一个视图中,供程序人员去调用
注意:在企业中,你查询的对象(表)他可能不是一张的表,可能是视图;你看到的视图的字段可能也不是真实的字段。
问题:我们想伪装一下这个视图的名字,或者是嫌调用的这个对象名字太长,怎么办?
同义词就是(对象的)别名,可以对表、视图等对象起个别名,然后通过别名就可以访问原来的对象了。
作用:
方便访问其它用户的对象 缩短对象名字的长度
同义词只有创建和删除操作。
【需求】在itcast用户下为视图scott.v_emp_dept20创建一个同义词emp20;
--查询验证:
友情提示:
如果工作中,你遇到一张"表"来查询数据,那么它一定是表么?不一定,可能是视图,也可能是同义词.
另外,任何对象都能起别名。下面的例子对emp表起个别名:
重点:
多表关联查询(oracle的语法,左外,右外 自连接) 子查询:any和all的面试题,子查询和多表查询的选择(面试) 分页:rownum+子查询!!! rowid:删除重复数据(面试) 两个新语法:批量插入(insert into table select ...) 复制表(create table tablename as select ....) delete和truncate的区别(面试),高水位,如何消除高水位(truncate,move) Oracle的事务和mysql的事务的不同(oracle在dml时隐式开启,必须手动提交(不建议隐式提交)) 约束的使用(外键是否要增加)(面试) 序列:创建(create sequence 序列名字)和插入数据的使用。 表空间-了解 创建用户:创建用户+赋予角色(connect,resource,注意:unlimited tablespace权限如果没有加上) 用户和方案的关系 跨域访问 视图, 同义词
转载于:https://www.cnblogs.com/beyondcj/p/6271086.html
相关资源:21天学通Oracle