我的安装参数:
全局数据库名:Jade
SID:Jade
sys,system的密码: 通用
SQL plus 的登陆:
1,程序组: 用户名: scott 或者system
密码: tiger
主机字符串: 只是在远程登陆时需要;
2,运行:sqlplusw scott/tiger@Jade 或者sqlplusw system/jade@Jade
注意:如果是本地登陆,@Jade则可以不写,就是主机字符串嘛
3,命令行:c:>sqlplus
被默认为自动启动的服务:
OracleServiveJADE
OracleTNSListener
OracleOracleAgent
OracleOracleHttpServler
Oracle的历史:
Oracle公司就是甲骨文公司,源自老板对中国文化的喜爱;
IBM公司的研究员Edgar Frank Codd来开了关系数据库软件
革命的序幕;
1977年Oracle公司的前身出现,Larry Elllison创业于实验室;
Larry Ellison认为1.0的软件不被人们信任,所以Oracle2.0是
第一个发布版本;
Oracle8I开始程序得支持Internet,I代表Internet;
Oracle9I版本后完全支持Java;
Oracle支持的PL/SQL语言:
完全支持SQL92标准;
PL:personl language;
Oracle使用Net8协议在客户端和服务器端传输数据时
加密和解密;我在想,这个协议如果被破解了,那
网络上被人收取的加密数据岂不被理解了?
TNS连接是Oracle两个节点间的通讯路径;
数据字典其实也是表,用户数据字典是用来存储当前用户
有什么样的表,试图,约束等信息的表而已;
.DBF数据文件;.CTL控制文件;.LOG日志文件;
Oracle系统包括磁盘文件和内存区的东西;
问问SQLServer怎么查一个数据库里有哪些表;
DML语言
字符数据一定要用单引号定界;
Oracle中要插入日期型时要用函数to_date('feb 3,05','mon dd,yy')
to_date可以将一个特定的字符串转换为特定格式的日期;
to_date使得用户非常灵活,你可以用自己定义的时间格式插入日期,
但是Oracle默认都会以一种形式来显示,可以修改:
alter session set NLS_date_format='yyyy;mm;dd';
每个Oracle连接到数据库时都会和数据库保持一个会话;所以有
修改会话的命令:alter session....
Oracle的内部都使用大写表示;Oracle用的是UTF-8字符集;
SQLPLUS的命令一个:set linesize 400把每行设置为400宽;
set pagesize xxx每页显示xxx行;
执行以前执行过的语句,用run,简写为r,或者/;
Oracle不可以一次执行做个语句;
解决的办法是:临时变量;用临时变量的话系统会与你进行交互
操作,靠,太方便了;
例如:insert into emp(empno,ename)
values(&id,'&name');
这样就会交互输入了;
使用子查询插入数据:批量插入其他的一个表的数据;
所谓的DML语句操作的对象都是数据,不是表;这包括:insert,update,delete;
事务
多个DML语句可以构成事务;
一个DDL语句可以构成事务;
一个DCL语句可以构成事务;
当第一条SQL语句被执行时,事务就自动开始了
当出现下面的事件时,事务就结束:
commit or rollback被执行时;
DDL or DCL被执行时(自动提交);
用户退出;
系统中止;
一个有用的命令:clear screen;
事务处理到底有什么作用:
试验一下:
1,执行insert into dept value(....)成功插入一条纪录后,在本
SQLPLUS窗口select * from dept的时候刚才插入的纪录是可见的;
而重新打开另一个SQLPLUS窗口就看不见刚刚插入的纪录;
原因就是第一个窗口中没有以上所说的四种结束事务的语句或者
操作;
可见事务没结束的时候,后台数据库并没有真正被改变,
暂时性的改变临时存在数据缓冲区中;
只有事务结束后,才真正写如这些数据;
简单地关闭sqlplus窗口并不能真确提交事务;(我说呢,昨天插入的
数据今天都不见了)
commit成功提交;
rollback取消未提交的事务操作;
事务一般远远不是你所想像的那么小,一般都很大;
所以我们不会老是回滚整个事务,所以我们用保存点来分割事务;
可以只回滚出错误的操作,不至于因为一部分的错误而连同
真确的操作一起撤消;
savepoint 的范围只是commit之前,如果提交了事务,那就无法回滚了,
当然无法回滚到一个保存点了,因为保存点已经失效了;
--------------------------------------------------------------------
--------------------------------------------------------------------
--------------------------------------------------------------------
2005-10-6
select语句
其实我们的select就是下面的三种:
选择行;
选择列;
连接运算;
//日期型也可以用+-*/运算,因为它本质就是数字;
//列的可运算查询使得我们不必在前台应用程序中对查询到的
数据进行运算,而是直接由数据库来完成;
使用别名:
表,列都可以使用别名;
方式:as或者空格或者用""把别名括起来;
可以使用||把查询到的几个列的数据连接成一个字符串:
select deptno||dname from dept;
//你必须有这样的认识:SQLPLUS与MS的查询分析器都是客户端应用程序
就好像你写的应用程序一样,它们提交SQL语句到数据库的时候都
经过了或者网络,或者缓冲区等介质;
//列名,表名是大小写不敏感的;字符串是大小写敏感的;
查询条件为空是因该是is null而不是=null;
--------------------------------------------------------------------
--------------------------------------------------------------------
--------------------------------------------------------------------
2005-10-7
SQL函数
两类函数:
单行函数;
多行函数;例如聚合函数。
单行函数:
1,字符函数:
转换函数:lower,.....
upper,.....
initcap,把一个字符串的每个单词的首字母转换为大写,其他的都
转换为小写;
字符操作函数:concat,字符串连接;concat('fuck','you')='fuckyou'
substr,取子串;substr('fuckyou',2,4)='ucky'
length,汉字与字母的行为位数是一样的;length('string')=6
instr,取得某个字母在字符串中所处的位置;
lpad,按固定位数输出字符串,不足的位数填充指定字符;
lpad(sal,10,'*')=5000;
/*我想你必须明白函数是怎么工作的?
其实对于一个函数,如果用到了参数,这个参数又是查询的对象,
则数据库会先查询出这个对象,然后再调用函数计算;
比如lpad('fuck',10,'*')我们也许其实要先查出'fuck'来,所以可能会是
lpad(name,10,'*');
如果要对一个常量字符串而不是查询得到的字符串进行以上的函数操作,那么:
只需要把相应参数替换,随便from 一个表就行了,当然我们有更好的
选择:
Oracle中有个名义表:dual,存储什么内容不重要,主要是
辅助我们用函数的;它只会返回一行;
*/
2,数值函数:
round:返回四舍五入值,round(45.926,2)=45.93;round(45.926,-1)=50;..
trunc:截取小数,trunc(45.926,2)=45.92
mod:求余,mod(1600,300)=100
3,日期函数:
Oracle内部存储格式:century,year,month,day,hours,minutes,seconds.
默认的日期格式:dd-mm-yy
sysdate函数返回系统的日期和时间;
//如果函数没有参数,可以不写括号;
//想要查看一个表的结构,或者说是它的所有列的定义,用desc table;
months_bewtween
add_months:它减轻了前台应用程序的工作负担:
当给一个月份加上几个月时出现跨年时,如果你在前台
应用程序里做这样的事情,那还必须对12取余,还要修改
数据库中的年份,但是如果用这个函数,前台程序实际上
什么都不用做,只管拿结果就行了;
其他的函数有着相同的效果;
next_day
last_day
round
trunc
2005-10-8
4,转换函数:
隐式转换;
显式转换:number要到character需要to_char;
character要到number需要to_number;
character要到date需要to_date;
date要到character需要to_char;
character是Oracle中的基本数据类型,你可以
这样理解:
character类型是其他类型转换的中继;
这些函数都有两个参数,第一个是要转换的对象,
第二个参数是格式;
想充分体会这些函数的重要性吗?
如果你的会话中现实日期的格式为:'dd-mm-yy'
而你试图插入一个以字符串表示的日期的话,
那你的字符串必须是'08-10-05'这样的匹配格式;
但是如果你试图插入的格式是'2005-10-08'的话,
你可以有下面两种选择:
1,修改会话为'yyyy-mm-dd';
2,用to_date('2005-10-01','yyyy-mm-dd');
NVL函数:将null值转换为一个实际的值,只有值为空时起作用;
用NVL函数的必要:
任何一个值和null值运算都会得到
一个null值,但实际上我们并不希望如此,
比如如果要计算一个员工年末应该得到的
工资加奖金,如果他没有奖金,那工资和
奖金相加就会是null,但实际上他至少应该拿
到工资而不是null, 所以可以用NVL函数来
指定一个值,比如给没有奖金的员工指定为0;
5,Decode函数:
这个函数非常有用,可以用加薪的例子来说明:
select job,sal,decode(job,'ANALYST',sal*1.1,
'CLERK',sal*1.15,
'MANAGER',sal*1.20,
sal) as jiaxin_salary
from emp;
这表示,工作职位为analyst的人,工资上涨10%,...
其他人员不涨工资;
//**几个重要的SQL-Plus命令:
save '\...' : 保存命令文件;
clear screen: 清楚屏幕;
get '\..' : 读取命令文件到缓存区,但SQL语句并不执行;
@ '\...' :加载并执行;相当于get+run;
connect scott/tiger,连接到oracle;
如果在用户名和密码后跟@主机字符串,就可以
连接到远程的数据库服务器;
//**Oracle的组织的一个很重要的认识:
Oracle中的表是针对用户的,也就是说一个用户对应拥有一些表,
而别的用户是不能直接访问的,必须做如下两件事情才可以:
1,受到要访问的表的用户的授权;
2,用表的拥有者用户.表名;
-------------------------------------------------------------
------------------------------------------------------------
------------------------------------------------------------Finished!
Oracle的锁
为什么要用锁:
多个用户同时对数据库进行操作的时候会产生冲突;锁可以防止多用户并行
的访问冲突;
//Sql-Plus的查看当前用户的命令:show user;
//Sql_Plus的修改提示符的命令:set sqlprompt ....>;
当另一个用户进行的操作还在缓冲区中,还没有commit的时候,
也就是另一个用户的事务没有结束的时候,本用户的对于同一个
资源的操作就会被挂起操作就会被阻塞;
这里所说的同一个资源叫做共享资源:
不仅指数据库行,而且也指其他的资源,如表;
当对同一资源进行操作的时候系统会自动加锁阻塞其中的
一个;但是当两个用户同时对一个表中的不同行进行操作的
时候,因为它们并没有同时对一个行资源进行更新,所以
系统并没有自动加锁来阻塞其中的一个用户;所以我们似乎可以
看到系统所认为应该自动加锁的资源是行,而不是表;那么如果
我们不想出现这种交叉修改的局面,是不是可以手动对整个表
进行加锁呢?
所以我们发现有两种类型的锁:
行级锁:tx
行被排他锁定;
在某行的锁被释放之前,其他用户不能修改此行;
使用commit或者rollback命令释放;
使用insert,update的时候自动被上锁;
用select ...for update语句获得行级锁:被加锁的对象是所有
被select 到的行;
防止其他用户修改此行,但可以查询;
具体的形式为:
如果锁定所有列:select..for update;
锁定特定列:select ..for update of ename;
不合理的是:当一个用户锁定时,别的用户不知道,只会等;
所以用select ..for update wait(second):
超过secong秒后加锁的用户还没有解锁的话,
其他等待也尝试加锁的的用户就会得到一个错误信息;
表级锁:tm
可以设置为三种模式:Lock table userID.tablename in [] mode;
共享:其他用户只能查询,不能更新,删除,插入;
多个用户可以同时对同一个表设置共享锁;
共享更新:in share update mode;
锁定要被更新的行,其他用户可以同时查询,
插入,更新未被锁定的行,即未被更新的行;
等于select..for update;
允许多个用户同时锁定表中不同的行;
排他:
仅允许其他用户查询,不允许插入,删除,更新;
在同时间仅允许一个用户在表上放置排他锁;
如果加上nowait的话,如果发现该表已经被锁定,
就不再等待,立即返回一个错误信息;
-------------------------------------------------------------
------------------------------------------------------------
------------------------------------------------------------Finished!
死锁
如上节讲的,如果A用户给一个表加了共享锁,而B用户也给同一个表加了
共享锁,那么A如果进行插入,删除,更新操作时,必须等待B来解锁,
而如果B又进行同样性质的操作,又在等A来解锁,这样就产生了死锁;
其实既然有锁,那就一定会有死锁;
Oralce数据库的表结构
通过图形化的界面可以直接创建表,而不一定是用SQL语句;
表的创建和维护:
create table tablename
(
...
...
);
number类型是int类型的父类型;
//凡是对表中数据操作的sql语句不需要带一个table关键字;
//而对表进行操作的sql,如create,drop,alter都需要带着
//table以表明是对表操作而不是表中的数据;
//对应着我们有insert,delete,update;
更改表:
添加列:alter table tablename add(新列名定义);
删除列:alter table tablename drop column 列名;
更改列:alter table tablename modify(列的重新定义);
增加约束:alter table tablename add constraint pk_stuno primary key(stuno);
删除约束:alter table tablename drop constraint pk_stuno;
rollback没什么用;确实没用;发现在数据库定义语言执行的过程中,没有事务的控制,做就直接做了,
这就引发了一个问题:有人在使用某个表的时候,我如果改变这个表的结构??
解决的办法是:alter table tablename set unused column 列名;
数据字典:desc user_constraints;
表分区:
范围分区法:按照列中值的分段在物理存储上也相应分区;列值有界限;
散列分区法:列值互不相同;
符合分区:范围与散列的总结,先进行大的范围分区,然后在
小范围中进行散列分区;
列表分区:当要参考分区的列的值没有边界,并且只有少数几个
数据的不断重复时,无论是范围分区还是散列分区都不再
适用,此时用列表分区;
分区的原则:要让各个分区存储的数据差不多;
把不想用的列置为无用状态;
在闲暇的时间:alter table tablename drop unused columns;
把无用状态的列删除;
如果要检索某个分区上的数据:select * from partition(p1);
表分区的维护
添加分区:alter table tabname add partition p5 values less than(120);
删除分区:alter table tabname drop partition p4;
截短分区: alter table tabname truncate partition p5;
合并分区:alter table tabname merge partitions p3,p4 into partition p6;
表分区的数据字典:
User_tab_partitions;
User_ind_partitions;
-------------------------------------------------------------
------------------------------------------------------------
------------------------------------------------------------Finished!
Oracle的数据库对象
同意词
数据库对象的替换名称,优点:
简化SQL语句;
隐藏对象的名称和所有者;
为分布式数据库的远程对象提供了位置透明性;
提供对对象的公共访问;
//如果在scott账号下的某个权限不足的话,可以通过下面的一系列操作来
完成:
conn system/[password] as sysdba;
grant create synonym to scott;
conn scott/tiger;
创建:
create [(public)] synonym [别名] for tablename;
删除:
drop synonym [别名];
数据字典:user_synonyms;
公有同意词的意义就是所有用户都可以访问,别人访问的时候不必再用用户.表名
来访问;比如system为scott.emp创建了employee别名,scott和其他用户都可以查询
这个别名,但是如果试图删除或者做其他操作,就会发现,即使是scott表也看不见
这个别名表,因为这个别名是system的;
序列
能够自动产生连续唯一值的数据库共享对象;
序列用于为主键提供值;
创建序列语句:
//用create创建的,就可以用drop删除;
create sequence seq
[increment by n]
[start with n]
[{maxvalue n|nomaxvalue}]
[{minvalue n|nominvalue}]
[{cycle|nocycle}]
[{cache n|nocache}] //在缓冲区存储生成的值;
属性:其实是函数
nextval 返回下一个可用的值;初始化序列值;
currval 获取当前的序列值;
数据字典:user_sequences;
序列是个什么东西呢?它就是在数据库中创建的一个供其他表
插入或者操作表数据的时候的一个方便的工具而已;
例子:insert into test values(seq.nextval);
select seq.currval from dual;
视图
视图显示了表中的一部分数据;
虚拟表,不实际存在数据;
好处:
提供了另外一种级别的安全性,也就是说我不告诉用户基表是
谁,就告诉一个可以让用户查询知道的视图;
隐藏数据的复杂性;视图的列可以首先从基表处拼合一个简单的列;
将应用程序与基表定义的修改隔离开来;
从另一个角度提供数据;
创建:create or replace view ....
order by....按照特定的顺序对行进行排列;
force 选项可用于创建带有错误的视图;
//你一直苦于当有一个SQL语句打错了的时候,如果
用r,/只能重新执行,无法直接只修改错误的地方而需要
全部重打;下面就有一个非常好用的方法来解决这个问题:
执行一句sql语句;
ed;//将会把上一行的sql语句写入afiedt.buf中;
修改afiedt.buf中你认为错误的地方,保存;
在sql-plus中使用r,/,将会执行修改后的afiedt.buf
中的sql语句 ;
所有的子查询结果都可以放在视图中,这就是为什么说视图简化了
表的复杂性,简化了sql的原因;
子查询可以排序,可以xxxx,所以得到的视图也可以是被排序后的,
被xxxx后的;
Oracle没有top关键字,为了得到前几行数据,我们:
Oracle中有两个隐藏的列:
rowid,对每一个行的唯一的物理映射的标识,
如果用具体的rowid来检索,速度飞快;
rownum,一个输出序列;如果想要检索出前5条的话,
就用where rownum<=5;
举个例子:create or replace view v_sal as
select ename as 姓名,sal as 工资
from emp order by sal;
select * from v_sal where rownum<=10;
这个例子将得到工资最低的前十个人;
视图更强大的功能是联接视图;
数据字典:user_views
删除视图:drop view
比如:
>create or replace view v_union as
select * from temp union all select * from temp1;
可以创建temp,temp1两个表的联合的视图;
视图的维护:
alter view v_union compile;
为什么这么做呢?这跟视图的原理是有关的,视图是系统通过编译sql语句得到
的一个虚拟表,也就是说这个表是基于系统的一次编译后的sql语句而存在的;
如果基表改变了,但视图还是基于原来被编译的sql语句,所以我们需要用
alter view v_union compile来重新编译视图;
-------------------------------------------------------------
------------------------------------------------------------
------------------------------------------------------------Finished!
索引
与表关联的可选结构;
快表,加快SQL;
减少磁盘I/O操作;
物理上索引存储在Oracle的文件上,称为索引表空间;
Oracle自动维护索引;
唯一值索引:定义在索引的列中没有重复的值;
Oracle自动为主键和唯一键列创建唯一索引;
create uinque index用于创建唯一索引;
//如果为某个表的某个列创建了唯一值索引,则即使这个列没有
唯一值约束,或者说主键不能重复的约束,也会被强制为不可重复
插入;因为索引是唯一值索引;
//注意,索引对表的作用是自动的,当你查询的时候,系统会
自动使用可用索引来提高速度,当你试图插入重复值的时候,
如果存在唯一值索引,就会自动阻止你;但是你不要试图象查询表一样
查询索引,索引只是后台的助手;
组合索引:连接索引;
在表的多个列上创建的索引;
组合索引的列可以按任意顺序排列;
对于在where子句中包含多个列的查询,可以提高速度;
因为索引已经把多个列组合在一起了哦!
例子:
scott>create index idx_empnoandeptno on emp(empno,deptno);
索引已创建。
scott>select * from emp where empno=7782 and deptno=10;
//注意,索引是自动被调用或者说使用的,当select语句执行的时候
自动用索引来检索;
反向键索引:
//普通的查询是全表扫描,而索引就可以让系统只扫描
查询列的索引,然后去扫描表的被选择行;
反转列中的每一个字节;
将数据插入操作分布在 整个索引上;
create reverse index;
//当某个列的值的前面几位都是一样的,只有后面的位有区别;
//当经常向表中添加数据,而不经常更新的时候;
位图索引:
bitmap index;
位图索引到底是干什么呀??
索引组织表:
表的数据和索引的数据存储在一起;
create table tablename(...primary key)
organization index;
其实索引是不存在的;
基于主键查询;
基于函数的索引:
其实很简单,就是用表的一个列的函数结果做索引;
同样,索引是在后台自动工作的;
当你再次使用那个索引创建时的函数查询表时,就会自动
调用已经用函数创建的索引,而不是从表中得到数据再用
函数计算;很显然,这加快了速度;
键压缩索引:用后缀项共享前缀项;compress;
分区索引:
索引存储在不同的分区中;
簇
有公共列的两个或者多个表的集合;
簇的表中的数据存储在公共的数据块中;
簇的表和普通表是一样的,只是多个表中的公共列
只存储了一份在公共的数据块中;
创建簇:
先创建簇,后创建组成簇的表;
create cluster;
插入数据的性能降低;
//在主键,外键关系表情况下用簇;
-------------------------------------------------------------
------------------------------------------------------------
------------------------------------------------------------Finished!
Oracle中的面向对象
Oracle既是ORDBMS也是RDBMS;
ORDBMS:
允许定义对象类型;
在关系数据库中存储复杂的业务模型;
开发应用程序的速度更快;
说白了,普通的关系数据库管理系统的数据类型都是
定义好了的;而面向对象的数据库管理系统允许用户
自己定义新的数据类型来存储到数据库中;
问题是RDBMS与ORDBMS是有冲突的;
//既然如此,总不能说说而已,我们应该可以通过SQL语句来创建我们的
类型,定义一个类,可以对类进行继承,多态的体验;
Oracle中可用的数据类型
抽象数据类型:
说白了,是父类;
创建过程:
create or replace type address as object
(
province varchar(20),
city varchar(20),
);/
你看看,这和定义一个类多么象,都是从
Object来继承;
接下来可以:
create table student
(stuname varchar(10),
stuAddress address
);
就象我们new出一个class一样;
insert into student values
('tom',address('jiling','changchun','qianjindajie'));
address(..,..,..)是构造函数;
同样也可以用tablename.stuAddress.province定位
查询省份;
update tablename set tablename.stuAddress=address(..,..,..);
如果要创建一个可以被扩展的类型,必须在最后加上
not final关键字;
create or replace type person as object
(
name varchar(10),
sex varchar(2)
) not final;
create or replace student under person
(
stuno int ,
stuscore int
);
这时,这个student 类型包含了他的父类的内容;
如果直接基于一个类型创建一个表,则这个表
叫做对象表:
create table stu of student;
则创建了一个和类型student定义的字段一样
的表,这个表可以进行数据操作而类型
是不可以的;
总之,面向对象是深入人心的;
//由于昨天没有在create or replace type..后加一个/,所以无法执行,
今天重新再看一遍这段视频学习一下:
创建类型:
create or replace type address_type
as object
(
province varchar(30),
city varchar(40),
street varchar(40)
);
/
从数据字典里查询:
desc user_types;//查看数据字典表的结构;
select type_name from user_types;//查看数据字典表里记录的类型的名字;
//数据字典就是表;
查看类型的结构:
desc address_type;//它跟表是如此地相像;
创建表:
create table studentobj
(
stuname varchar(10),
stuaddress address_type
);
desc studentobj;
----
stunamme varchar(10);
stuaddress address_type;
向表中插入数据:
insert into studentobj values
('jade',address_type('gansu','qingyang','xiaoxian34'))
/
查询时的规则:
你可以
select stuname, stuaddress from studentobj;
但是如果你试图查询详细到stuaddress的每个属性上,
则select stuaddress.province ... from studentobj;是行不通的;
必须给表一个别名:
select s.stuaddress.province ... from studentobj s;
更新:
update studentobj set stuaddress=address_type('','','');
如果只修改stuaddress的一个属性而不是全部,可以:
update studentobj s set s.stuaddress.province='beijing'
创建一个可被继承的类型:
create or replace type person
as object
(
name varchar(10),
sex varchar(2),
birth date
) not final;
/
创建继承子类型:
create or replace type student_type
under person
(
id int,
score int
);
/
创建对象表:
create table student of student_type
/
创建的对象表和对象类型的定义完全一样;
对象表和普通的关系表是不一样的;
当然在具体操作上只是create的语句不一样;
而其他的操作都一样;
创建对象表深刻体现了面向对象:用一个模型student_type来
new 出一个student,而不象关系表那样用基本数据类型来
定义一个表;
一句无法解释的命令:
insert into student
select student_type('mike','m',to_date('05-2-2','yy-mm-dd'),1002,78)
from student where name='ppp';
其实也可以解释:
这个语句追求的不是真要从from studnet where name='ppp'中得到一个数据,
而是追求希望from studnet where name='ppp'返回一个true,其实本语句的
的真正目的就是直接插入student_type(...),只不过希望from子句把一下关而已;
可是我们为什么要使用它呢?有什么好处?
-------------------------------------------------------------
------------------------------------------------------------
------------------------------------------------------------Finished!
面向对象数据库中存储的是对象,对象有自己的行为和属性;
行为体现为类型的函数或者过程;属性体现为字段;
对象表确实有优势吗?
基于抽象类型创建关系表:和其他表的创建一样;
基于抽象类型创建对象表:create table 对象表名 of 抽象数据类型;
抽象类型可以复用:也就是说一个抽象类型中可以包含另一个抽象类型做为一个字段;
构造函数是默认创造的,参数包括类型的字段;
如果要插入数据到对象表,有两种方式:
一种就是insert into tablename values(字段1,字段2,....);
另一种就是我们如果想直接用构造函数构造一个大字段直接插入,
这时候不需要values,但必须用slect:
insert into tablename select 构造函数(字段1,字段...) from xxx;
创建带方法的类型:
首先说方法的定义:如果有返回值,用member function...
没有返回值,member procedure...
****以后再说;
可变数组
声明一下Oralce的oop中使用下列的对象类型:
·抽象数据类型;
·可变数组;
·嵌套表;
·对象表;
·对象视图;
可变数组会根据存储数据的大小来真正存储数据而不是占用固定的空间,这类似
Java中的ArraryList类;
关系型理论中不允许一个表中的一个记录中存储其他表记录,
而Oracle中是支持的;这不是违反了数据的原子性原则吗?
但是这样有好处:
在用户查询的时候比两个表进行关联查询效率高;
所以说可变数组也可以做为一条记录的一个字段被存储在一个表中,
当然这是违反关系数据理论的;
创建可变数组的例子:
create or replace type mingxitype as object
(
goodsid varchar(15),
incount int,
providerid varchar(15)
);
/
create or replace type arrmingxitype as varray(100) of mingxitype;
/
create table instock
(
orderid int primary key,
indate date,
mingxi arrmingxitype
)
/
insert into instock
values(1001,to_date('2005-10-19','yyyy-mm-dd'),
arrmingxitype(mingxitype('101',10,'so1'),
mingxitype('193',30,'j02'),
mingxitype('104',32,'i92')
)
)
/
//table函数可以把可变数组转换为关系表的形式显示出来;
select * from table(select s.mingxi from instock s where orderid=1001)
GOODSID INCOUNT PROVIDERID
--------------- ---------- ---------------
101 10 so1
193 30 j02
104 32 i92
可变数组的元素不能单独改,必须全部改;
所以可变数组适合的场合是:
用户不会修改的数据,历史性的数据就适合用可变数组;
删除数据是通用的;
//可变数组的基类型是用户定义的;所以这个基类型也可以是一般数据类型,比如int;
create or replace type arrayint as varray(30) of int;
-------------------------------------------------------------
------------------------------------------------------------
------------------------------------------------------------Finished!
嵌套表
就是表中之表;可变数组是表中之抽象类型;
嵌套表可以有效地代替多个表之间的连接;
本质和可变数组是一样的;在一个表中的某个列,可以存储其他数据类型的数据;
可变数组把这个列的一个节点当作一个数组,这个表就一个列,可以存储as varray()
定义的数量个行的数据,其实每一行就是一个of关键字后面的类型的数据,如果这个类型是
抽象类型,则实际是一个对象表;
嵌套表把这个列的一个节点当做一个表,这个表就一个列,可以存储无限个行的数据,
其实每一行就是一个of关键字后面的类型的是数据,如果这个类型是抽象类型,则
实际是一个对象表;
说白了,嵌套表实际是一种更广泛意义上的可变数组;
create or replace type mingxitype as object
(
goodsid varchar(15),
incount int,
providerid varchar(15)
);
/
create or replace type nesttype as table of mingxitype;
/
create table instocktable
(
orderid varchar(13) not null primary key,
indate date,
operator varchar(12),
mingxi nesttype
)nested table mingxi store as mingxitable
/
insert into instocktable
values
('2002',to_date('2005-10-20','yyyy-mm-dd'),'fuck',
nesttype(mingxitype('101',10,'so1'),
mingxitype('193',30,'j02'),
mingxitype('104',32,'i92'))
)
/
嵌套表的优势:
比较多表关联查询,效率高;
*********
对象表
因为对象类型可以被定义为一个表的一个字段,也可以被定义为整张表,所以有:
行对象:在对象表中拥有整个行的对象;
列对象:在较大行中拥有某些表列的对象,或者其他对象的属性;
对象表中的每一行都是一个对象;
每一个对象都有一个表示OID;oid是全局唯一值;
ref操作符用于引用行对象;
用ref来获得oid值:
select ref(a) from otable a;
deref操作符返回行对象的值;
ref用法举例:
create or replace type officetype as object
(
id varchar(10),
typename varchar(10)
);
/
create table office of officetype
/
SQL> select * from offi
ID TYPENAME
---------- ----------
1001 财务
1002 人事
1003 伙食
1004 后勤
/
create table worker
(
workerid varchar(10) primary key,
workername varchar(10),
workeroffice ref officetype scope is office,//workeroffice这个字段的类型是引用类型;
phone varchar(16) // 这个引用类型的类型是officetype型的;
) //范围是office表里的数据;
/ //本质上这个字段存储的对象的oid值,用来引用;
向这个表中插入数据就不能用values的,因为oid的值是你自己无法敲打出来的;
所以我们用ref来得到office表中的一个行(对象)的oid值,然后插入worker表
的workeroffice字段中;
insert into worker select 'c001','jade',ref(cao),'010-23333'
from office cao where id='1001'
/
SQL> select * from worker;
WORKERID WORKERNAME
---------- ----------
WORKEROFFICE
-----------------------------------------------------------------------------
PHONE
----------------
c001 jade
000022020871387910C69D4A2EACF886D61B4BB847231DEB0B46EA4B2CA4FEA46BE43008B6
010-23333
/
000022020871387910C69D4A2EACF886D61B4BB847231DEB0B46EA4B2CA4FEA46BE43008B6就直接定位
指向office表中的一个对象;
deref:取得oid指向的行中的数据;
SQL>select workerid,workername,deref(w.workeroffice),phone from worker w
WORKERID WORKERNAME
---------- ----------
DEREF(W.WORKEROFFICE)(ID, TYPENAME)
--------------------------------------------------------------------------------
PHONE
----------------
c001 jade
OFFICETYPE('1001', '财务')
010-23333
/
value函数以对象的方式显示数据;
示例:
SQL> select * from office;
ID TYPENAME
---------- ----------
1001 财务
1002 人事
1003 伙食
1004 后勤
SQL> select value(o) from office o;
VALUE(O)(ID, TYPENAME)
---------------------------------------------
OFFICETYPE('1001', '财务')
OFFICETYPE('1002', '人事')
OFFICETYPE('1003', '伙食')
OFFICETYPE('1004', '后勤')
*********
对象视图
将一个关系表打扮成一个对象表;说是打扮,所以说并没有真正把
关系表转换成对象表;
下面演示一下如何把scott表中的dept关系表打扮成对象表:
首先必须创建一个供视图参考的类型:
create or replace type depttype as object
(
deptno number(2),
dname varchar(14),
loc varchar(13)
);
/
为了得到oid,这里用的是通过转换原关系表的主键得到一个oid:
create view deptview of depttype with object oid(deptno)
as select from dept;
*
/
select * from deptview;
DEPTNO DNAME LOC
------ -------------- -------------
10 ACCOUNTING NEW YORK
20 RESEARCH DALLAS
30 SALES CHICAGO
40 OPERATIONS BOSTON
/
SQL> select ref(d) from deptview d;
REF(D)
--------------------------------------------------------------------------------
00004A038A0046D2C2E4D8D8AC427389FD05BBC9B8B2D00000001426010001000100290000000000
090602002A00078401FE0000000A02C10B0000000000000000000000000000000000000000
00004A038A0046D2C2E4D8D8AC427389FD05BBC9B8B2D00000001426010001000100290000000000
090602002A00078401FE0000000A02C1150000000000000000000000000000000000000000
00004A038A0046D2C2E4D8D8AC427389FD05BBC9B8B2D00000001426010001000100290000000000
090602002A00078401FE0000000A02C11F0000000000000000000000000000000000000000
00004A038A0046D2C2E4D8D8AC427389FD05BBC9B8B2D00000001426010001000100290000000000
090602002A00078401FE0000000A02C1290000000000000000000000000000000000000000
REF(D)
--------------------------------------------------------------------------------
下面把emp表打扮成对象视图;这里的问题就是emp中的一个列是
deptno,恰好是dept表的主键;既然dept表中的行已经存储为对象了,
那我们就可以直接在emp的deptno字段用指向对象的引用了;
也就是说:***关系表中,主表是通过一个外键值来找到从表中的某一行数据的;
****而对象表中,主表是通过存储的从表的某一行的oid来找到具体的数据的;
make_ref(deptview,deptno) deptoid可以把主表中的一个具体的deptno值转换成
deptview中的oid;
create view emp_view as select make_ref(deptview,deptno)
deptoid,empno,ename from emp
/
这时候emp_view就是emp的对象表形式了;
------------------------------------------------------------------------------
------------------------------------------------------------------------------
-----------------------------------------------------------------Finished
Oracle的安全
第一:用户管理*******************************************
用户至少需要会话的权利,否则连接也不成功;
用户在会话的权利上,应该有其他操作的权利;
Oracle的用户和口令不区分大小写,真是让人大跌眼镜;
Oralce中,所有用户必须明确被授权,才可以操作;
SQL Server中,创建的用户自动就拥有了一些权限;
Oracle不依赖操作系统;SQL Server依赖Windows;
MicroSoft假定大多数用户都是合法用户,采取乐观态度;
Oracle首先假定用户都是不安全的,采取悲观态度;
Oracle中的用户是互相隔离的,称为用户模式;
内置用户:
sys,网络管理员,最高权限;
当你试图输入了用户名:sys
密码:通用
之后,你发现连接不上;
而输入 用户名:system
密码:通用
或者 用户名:scott
密码:tiger
的时候都可以连接,所以你认为
sys的权限没有system高;
其实正是因为sys的权限高,所以你必须以
dba的身份来登陆:sys/通用 as sysdba
//可以使用数据字典user_users来查看当前用户管理的用户:
select * from user_users;
而dba_users可以查看dba管理的用户;
system,只管理本机上的数据库;
而all_users查看所有用户,只能由dba来查看;
******创建用户:
create user 用户名 identified by 口令 [externally]
[default tablesapce 表空间名]
[temporary tablespace 临时表空间名]
[quota 整数 K|M|unlimited on 表空间名]
//注意:创建用户必须有dba的权限;
******查询用户:
其实就是对表user_users/dba_users/all_users进行查询,
只不过这里不把他们叫表,叫数据字典;而且数据字典是系统
维护的;
*******修改用户:
alter user.....//后面和创建一样;
Oracle中一个实例就是一个数据库,这个数据库相当与SQL Server的全部数据库;
Oracle的一个数据库被分为很多个表空间,每个表空间相当于SQL Server中的一个数据库;
实例演示:
create user student_user
identified by student
default tablespace users
temporary tablespace temp
quota 5m on users
quota 3m on temp
/其中,users,temp都是内置的表空间,student_user在users里有5m空间,在temp里有3m;
新创建的用户是没有权利的:
SQL> conn student_user/student;
ERROR:
ORA-01045: user STUDENT_USER lacks CREATE SESSION privilege; logon denied
警告: 您不再连接到 ORACLE。
*****限制用户
锁定:alter user 用户名 account lock;
效果:
SQL> alter user student_user account lock;
用户已更改。
SQL> conn student_user/student;
ERROR:
ORA-28000: the account is locked
警告: 您不再连接到 ORACLE。
解锁:alter user 用户名 account unlock;
口令无效:alter 用户名 password expire; 当用户创建了很多表,
如果直接删除用户,它下面的表都将被删除,所以我们可以
只使得它的口令无效;
//可见,表是用户的手下,用户没了,用户创立的表,占用的空间都就没了;
//所以,一般情况下,我们不要删除用户;
****删除用户:
drop user 用户名[cascade]
//cascade是强制删除,即使有别人正在用这个用户的表;
//数据库管理语句是自动结束事务的,没有rollback的机会;
第二:权限管理***********************************************
授权:grant [系统特权名] [角色] [on 被授权操作表名] to [用户名列表]
[public][with admin option]
如果是dcl语句,就不用on 被授权操作表名
grant all on student to public:把对student的所有权限授予所有用户;
数据字典:user_sys_privs
select * from user_sys_privs
权限收回:
revoke 权限列表 on 表 from 用户;
SQL> revoke create table from iam;
撤销成功。
撤消只是撤消本次授权的权限,所以如果某个用户原来就有某个权利,
而你又给它授了同样的一个权利,然后你收回这个权限的时候,它原来
就具有的这个权利还是有的;
第三:角色管理*****************************************
因为一个用户可能需要某些权限的集合,当我们得到一新的用户的时候,我们需要给一个
用户依次授权每个它需要的权限;角色正是一个权限的集合,用户可以直接被授予这个
角色,用户自然就拥有了它的角色所拥有的权利;
创建角色:
create role 角色名 [no identified|identified by 口令|externally]
not identified:指出授予该角色的用户在使用时不需要检验;
identified by:指出授予该角色的用户在使用set role命令时需要检验;
收回权限:revoke 权限 from 角色名;
//角色就是权限的集合;
实例:
create role student_role
/
grant create table,create session,create view to student_role
/
grant student_role to scott
/
revoke create view from student_role
/
角色的某个权限被收回的时候,被授予该角色的用户的该权限也相应被收回;
.......................前面5章回顾.............................
一个表空间就对应着一个数据文件,里面可以存储多个用户的表;
但是一个表只能在一个表空间里;
Oracle就三种基本数据类型:字符;日期;数值;
还有巨型的对象类型,可以存储电影;
三种语言:数据操作语言;数据定义语言;数据控制语言;
-------------------------------------------------------------
------------------------------------------------------------
------------------------------------------------------------Finished!