==============================================
这一章重点是约束
==============================================
非空约束: not null (nn)
create table ( c1 number not null,c2 number)
非空约束可以在desc这个表的时候在null?列可以看到not null
PK也是非空属性。。因为PK是唯一且非空
insert into test(c2) values(1)
就会报错
非空约束 只能定义为列级约束
唯一性约束:(unique key) uk
create table test(c1 numner unique, c2 number)
insert into test values(1,1)
第一次正确
insert into test values(1,1)
第二次报错
insert into test(c2) values(1);
不会报错,unique是在有值的时候唯一。对于null不去追究他是否为重复值
所以插入多少次insert into test(c2) values(1)无论插入多少次都不会报错。
pk = uk +nn
唯一性约束的表级约束:
create table test( c1 number,c2 number,unique(c1))
级联删除
on delete cascade
级联置空
no delete set null
check 约束:
create table test(c1 number check (c1>1000));
定义c1的值要小于1000,如果insert into test values(1000);
就会报错。
insert into test values(1000)
*
ERROR at line 1:
ORA-02290: check constraint (SD0603.SYS_C005328) violated
实现的业务规则,比如定义最低工资不能低与1000
不允许使用伪列,函数,其他计算的值
他也可以定义在表级和列级
创建一个脚本文件,(vi),里面加上create table的语法。
加上约束条件
@脚本文件执行。
sqlplus 用户名/密码 @脚本文件名 (在shell下直接运行脚本文件的方法)
约束名的存在形式是用户名.约束名
不是和表走的。所以定义约束名的话,也要注意不要和同一个用户下面的其他约束名重复
凡是能够用约束实现的,就不要自己去写代码
可以用一个已知的表来建立新的表
create table s_emp_42 as select * from s_emp where dept_id =42
desc s_emp_42
用42部门的所有记录新建一张表。注意as的用法
非空约束可以带过来。其他约束会丢失。。
用已知表来创建其他表的时候。新表里只保留非空约束
如果只想要老表的结构。不想要老表中的数据:
create table s_emp_42 as select * from s_emp where 1=2;
写一永假式,让任何时候条件都不满足。这样就可以不拿到任何数据。只拿到结构
如何知道一个表中有哪些约束:
查阅数据字典视图
desc user_constraints
select constraint_name,constraint_type,table_name from user_constraints where table_name = 'S_EMP'
输出:
CONSTRAINT_NAME C TABLE_NAME
------------------------------ - ------------------------------
S_EMP_ID_NN C S_EMP
S_EMP_LAST_NAME_NN C S_EMP
S_EMP_COMMISSION_PCT_CK C S_EMP
S_EMP_ID_PK P S_EMP
S_EMP_USERID_UK U S_EMP
C列为约束类型。c为check或者not null,p为pk,u为uk,R为fk,v为视图的with check option约束,o为视图的read only约束
search_condition段可以看到到底是check还是not null
查看约束名对应的段名
desc user_cons_columns
查看S_EMP_ID_PK约束名定义在哪个一个段上:
select column_name,position from user_cons_columns where constraint_name='S_EMP_ID_PK';
POSITION
----------
ID
1
position 的意思是:联合主键时字段的位置比如pk(c1,c2),那c1就是1,c2就是2
user_constraints和constraint_name的关系是:约束名相等
1 select c.constraint_name,c.constraint_type,
2 cc.column_name
3 from user_constraints c ,user_cons_columns cc
4 where c.constraint_name = cc.constraint_name
5* and c.table_name =cc.table_name
SQL> /
数据字典
user 自己的 users
all ------->---------> views
dba indexs
constraints
SQL> desc dict;
Name Null? Type
----------------------------------------- -------- ----------------------------
TABLE_NAME VARCHAR2(30)
COMMENTS VARCHAR2(4000)
1 select table_name from dict
2* where table_name like '%CONS%'
SQL> /
可以查看所有包含cons视图的表名
dml数据操作语言
insert update delete
事务的概念:数据库里面流淌的是很多的事务(不是DML语句)
oltp:联机事务处理
数据类型、约束、基本语法搞清楚
insert语句:
insert into table
values (102,null,....)
insert into table(id,name) 这种方式比较常用
values(102,'mis')
insert into 表名(指定的字段) values(数据)
日期问题:
*****************************************************************
insert into s_emp(id,first_name,last_name,start_date)
values
(25,'Donna','Smith',TO_DATE('01-JAN-99 09:00','DD-MON-YY HH:MI'));
update s_emp
set dept_id = 100
where id = 2;
delete from s_emp;
delele from s_emp
where start_date>TO_DATE('01.01.1996','DD.MM.YYYY')
*****************************************************************
insert into s_emp_42 select * from s_emp where dept_id=42;
一次插入多行记录,把s_emp表中42部门的数据插入到s_emp_42表中
update 对存在的的记录进行修改
update 表名 set 字段名=值 where写条件
update s_emp set dept_id = 10 where id = 2
把员工id为2的员工部门号换为10
update s_emp set commission_pct=10;把s_emp把所有的的提成都改成10;
把一个字段的值改为空用UPDATE
把记录删除使用delete
删除多少条,取决与where条件
delete from s_dept where region_id = 1;
这个在有子表引用这一项的时候。而且没做级联删除的时候会报错。
拿delete删除一个记录数很多的大表的时候,会很慢的
用delete删除之后,数据是可恢复的
delete删除表之后。表占用的空间一点也没释放出来
oralce只是把记录打个删除标记,并没有真正的删除数据
所以delete不适合删除一张大的表
ROWID字段:
1 select rowid,s_dept.*
2* from s_dept
SQL> /
ROWID ID NAME REGION_ID
------------------ ---------- ------------------------- ----------
AAAIlTAAIAAABeqAAA 10 Finance 1
AAAIlTAAIAAABeqAAB 31 Sales 1
AAAIlTAAIAAABeqAAC 32 Sales 2
AAAIlTAAIAAABeqAAD 33 Sales 3
AAAIlTAAIAAABeqAAE 34 Sales 4
AAAIlTAAIAAABeqAAF 35 Sales 5
rowid是地址,天生的主键。非空,唯一。同理还有rownum
rownum只能取1或者<=n,因为他只有取过了才知道下一个的num号.所以不能直接取N
用rownum可以实现分页显示
select first_name ,rnum from ( select rownum rnum,first_name from s_emp where rownum <= 10 ) where rnum between 5 and 10;
显示5到10条记录。
下面是查询哪个人的工资比本部门的平均公司高:
select e.first_name,e.salary,avgsal
from s_emp e,(select dept_id,avg(salary) avgsal
from s_emp
group by dept_id )a
where e.dept_id =a.dept_id
and e.salary > a.avgsal;
FIRST_NAME SALARY AVGSAL
------------------------- ---------- ----------
Carmen 2500 2025
LaDoris 1450 1247.5
Roberta 1250 1081.66667
Ben 1100 900
Antoinette 1300 1050
Marta 1307 1089
Mai 1525 1160
Elena 1400 1247.5
Akira 1200 1081.66667
Sylvie 1100 1089
10 rows selected.
事务在生活中的例子:工资卡A,为了防止过度消费,办理了一个消费卡B。每个月从卡A转帐到卡B上800块钱。
对应数据库中的DML语句:
卡A:update 帐户表 set 余额 = 余额-800 where 帐号=卡a卡号;
卡B:update 帐户表 set 余额 = 余额+800 where 帐号=卡b卡号;
两条语句共有的特点:(原子操作特点,这两个动作是不可分割的)
卡A-800后数据库down机的话。再启动起来之后需要回滚,否则就会出现问题卡A钱少了。卡B没有加钱
这样就引进了transactions
定义一个数的开始:上一个数的结束,就是下一个数的开始
事务里面包含的语句:DML(主要的) dml语句可以回滚的。也就是说执行一个dml语句之后,没有自动提交commit,只有在当前session是做完dml语句之后的结果。其他session看到的还是自己本session修改的数据,除非修改方commit事务
当发出;commit或者rollback的时候事务结束(commit确认成功,rollback回滚,撤消)
如果发出ddl或者dcl语句的时候也会自动结束事务(ddl语句结束时,会自动调交一个commit,ddl语句是不可以回滚的)
事务没有提交之前称为活动事务,事务的隔离级别为:read commited
如果一个session修改了一个记录,但是没commit或者rollback的话。其他session如果要对这条记录做dml,就会等待。除非修改方提交修改
做dml操作时数据库会自动给这个记录加一个表级共享锁和一个行级排它锁
共享锁:大家都可以加的锁,一个session加上之后。别人也可以再加一个锁
排它锁:一旦一个session加了,别的session是加不上的,别的session会wait原来的锁取消掉之后再继续操作
如果加一个表级排它锁,就会把数据库的并行操作改为串行排它锁
ddl操作会把这个表加上一个ddl排它锁,加不上的时候会报错退出,并不会wait
rollback 一旦提交之后,是不能回滚了的。
rollback 是把整个事务回滚掉
正常退出:自动提交commit 非正常退出:自动提交rollback
也可以做保留点:savepoint,回滚的时候可以选择性回滚
alter table 修改表结构
drop table
rename
truncate table
这些语句都会自动提交一个commit
alter table 对结构和约束的修改
alter table test add (c3 varchar2(10) ) ; 把test表加一个长度为10的varchar2字段
alter table test add (c4 varchar2(10) not null ); 这样是错误的,因为没给他实际的值,又说not null
alter table test add (c4 varchar2(10) default 'abc' not null); 这样就可以了。
删除一个列:(8i以上版本)
alter table test drop column c4; 删除test表中的c4字段
alter table test drop(c4);这样也可以
把字段改名:(9i.0以上版本)
alter table test rename column c1 to c11; 把test 表中的c1字段改名为c11
修改段类型:
alter table test modify (c3 varchar2(20) ) 修改test表中的C3字段宽度为20,注意如果改小宽度的时候最小的宽度应该等于字段内最大的宽度
alter table test modify (c3 not null); 修改test表中c3字段为非空约束,但是要注意在添加非空约束的时候,确保字段内没有NULL
只有非空约束是用modify来修改的
修改约束(增加约束)
disable 一个约束,使这个约束临时失效,还可以用enable使他生效,如果删除一个约束,就是不可恢复的了。除非再次添加
alter table test add constraint test_wtx_pk primary key(c1); 在c1字段增加pk约束,表级约束的语法
alter table test drop constraint test_wtx_pk; 删除约束名为test_wtx_pk的约束
因为一个表只有一个主键,所以可以用 alter table test drop primary key; 来删除主键约束
也可以违反一次约束,来看错误提示获取约束名。或者查看视图来获取约束名
alter table parent drop primary key;是删不掉的。因为child表引用了这个主键约束。先要删除child里的fk;
也可以alter table parent drop primary key cascade ;级联删除,把parent表的PK删掉之后,child里的对应的FK约束也被删除了。
alter table parent disable primary key; 使parent里的pk临时失效(可以级联失效,但是不能级联生效)
alter table parent enable primary key; 恢复parent里的pk,但是这里要保证pk里的值全部是非空而且唯一的,否则恢复不了
rename test to test2; 把test表改名为test2(oracle 7开始支持)
Truncate table s_emp;
删除所有数据,不同于delete from s_emp;,它释放了表占据的空间。磁盘空间,表结构还在,数据没了(和delete对比)
sequence:自动产生唯一值,主要用与产生主键值,代替应用程序代码
create sequence s1;产生一个唯一值,下面以test表为例,c1为pk
insert into test values(s1.nextval)
s1.nextval--->伪列
上述插入4次,得到结果:
C1
--------
1
2
3
4
sequence只能保证唯一,但是不保证连续,他还有另外一个伪列:s1.currval,显示当前s1里的数值
注意:sequence产生的唯一值,是面向session,必须选取一次才知道。如果再开一个session,那么就不能直接的查看s1.currval和s1.nextval
sequence默认从1开始,默认步长1,最大取值缺省无,最小取值缺省无,循环缺省无,cache为一次产生多少个值在内存里。用的时候从内存中取,cache可能造成nextval不连续。但是速度会加快,系统缺省的cache是20,实际应用中可以设置到1000-2000
user_sequence里面有用户的sequence信息
alter system flush shared_pool;刷新内存。清一次内存。要在sysdba里的system下做
alter sequence后面跟上定义sequence时候的参数。就可以修改sequence(不可以修改修改的起始值,最大值不能小于现有值)
drop sequence 名字。删除指定的sequence
views
test叫基表base table test_v叫做test的视图。他不占用任何存储空间
create view test_v as select * from test where c1 = 1;
把test表里c1=1的记录全部过滤出来,查看视图test_v就可以直接的查看test里的c1=1的记录
从某种意义上说,视图就是一个selcet语句的缩写,在user_view可以找到详细的信息(text段里可以看到他的过滤条件)
使用view不能提高查询性能
8i以后提供了multi view 物化视图(MV),占用物理空间,可以提高查询速度。但是实时性能比较差,当基表的数据变化了的时候,就不可以及时反映出来,是用在数据仓库里做聚合表的
使用view的好处:简化查询、限制数据的访问、相同的数据以不同的面貌呈现出来
create or replace view 视图名; 如果视图已经存在就覆盖(用来修改视图)
create or replace force view 视图名; 基表必须存在才可以建立视图。noforce是基表不需要必须存在
with check option 做限制
简单视图(可以DML),复杂视图(不能DML)。
不可以删除:select 语句里有组函数。有group by子句,dintinct命令
不可以修改:上述情况,还有其中的列定义为表达式,有rownum伪列的时候
不可以插入:以上情况,还有没有把非空的包括进去的视图
create view test_v as select * from test where c1=1 with read only;做限制,只读,不能插入
create view test_v as select * from test where c1=1 with check option; 做限制,只能插入1,因为where子句里限定条件是1
select constraint_name,constraint_type from user_constraints; 显示当前用户下所有的约束
C列为约束类型。c为check或者not null,p为pk,u为uk,R为fk,v为视图的with check option约束,o为视图的read only约束
drop view 视图名;删除视图
synonym同义词:
create synonym sd_s_emp for sd0603.s_emp;把sd0603.s_emp起一个同义词叫sd_s_emp,默认是私有的,只能自己用
create public synonym sd_s_emp for sd0603.s_emp; 创建一个公共的同义词sd_s_emp,每个用户都可以用
grant create public sysnonym to sd0603;授权sd0603可以创建公共同义词的权限;
drop synonym 同义词名;删除定义同义词
index:是一个纯数据库动作,对系统的性能影响非常大
oracle里面找数据,是从头到尾都找一遍(没有索引的情况下),full table scan 全表扫描
查字典的动作对应到数据库里查询方式,就是索引扫描,能够很快的定义到要查询的数据上
建立索引是在字段上建立的。
索引项里包含key值,记录的位置(记录的位置用rowid)
rowid可以提取出来。这条记录是属于哪个表的。是属于哪个文件的哪个data block的,哪个row上(从这里AAAIlTAAIAAABeqAAA读取)
各个索引项的组织方式:各个索引项组织成一个B*tree(索引树、平衡树)可以用二叉树来想一下
叶子节点里放key值和rowid
比根节点大的在下面,比根节点小或者等于根节点的在上面
索引是用户自己建立的
索引里的数据是用户做dml操作的时候触发系统自动添加的
做update的时候。索引里是先删除原来的数据。再插入新的数据,因为索引里的数据是排序的
索引本身也是一个数据库对象,本身也占空间,物理上和表是分开的。逻辑上是在一起的,drop一个表的时候,相应的索引也会被删除
使用rowid快速定位记录的物理位置,减少了磁盘的输入输出
索引可以自动创建,当我们创建PK和UK的时候。系统会帮我做一个唯一性索引
其他时候,为了加快查询速度,手工建立索引
索引的类型:唯一性、非唯一性、单行单列索引,联合索引
create index testc1c2 on test(c1,c2); ---->建立一个联合索引(适用与c1和c2经常同时出现在where子句的情况)
create index 索引名 on 表名(字段名);
建索引:1、表的记录越多,建索引的效果就越明显 2、经常作为查询条件的字段 3、查询结果少的字段 4、连接条件上
5、有大量的空值 (索引会忽略空值)
user_index索引的名字信息
user_ind_columns索引是在哪个字段的,是否是联合索引
自动建表的脚本位置:
{$oracle_home/rdbms;cd demo;summit2.sql}
windows下要设置要下环境变量:set LANG=AMERICAN_AMERICA.US7ASCII
替换变量:
define/accept/&