Oracle基础(三大范式、表约束、增删改、事务等)

三大范式

设计原则: 建议设计的表尽量遵守三大范式。

    第一范式: 要求表的每个字段必须是不可分割的独立单元
    第二范式: 在第一范式的基础上,要求每张表只表达一个意思。表的每个字段都和表的主键有依赖。         
    第三范式: 在第二范式基础,要求每张表的主键之外的其他字段都只能和主键有直接决定依赖关系。

创建表和约束

/*
数据库中的五大约束:
1.主键约束(Primay Key Coustraint) 唯一性,非空性;
2.唯一约束 (Unique Counstraint)唯一性,可以空,但只能有一个;
3.默认约束 (Default Counstraint) 该数据的默认值;
4.外键约束 (Foreign Key Counstraint) 需要建立两表间的关系;
5.非空约束(Not Null Counstraint):设置非空约束,该字段不能为空。

另外还有一种check约束:设置后可以约束值范围等。
*/

--MySQL创建表语句users(id整型/name字符串/birthday日期型,默认今天)
drop table if exists users;
create table if not exists users(
   id int(5) auto_increment primary key,
   name varchar(4) not null,
   birthday date default '2018-2-07'
);

--使用oracleSQL,创建用户表users(id整型/name字符串/birthday日期/sal整型,默认今天)
create table users(
  id number(5) primary key,
  name varchar2(8) not null unique,
  sal number(6,2) not null,
  birthday date default sysdate
);

--删除表进入回收站
drop table users;

--查询回收站中的对象
show recyclebin;

--闪回,即将回收站还原
flashback table 表名 to before drop;
flashback table 表名 to before drop rename to  新表名;

--彻底删除users表
drop table users purge;

--清空回收站
purge recyclebin;

--测试如下类型
--(1)number(5):
insert into users(id,name,sal) values(1,'A',6666.66);     
insert into users(id,name,sal) values(11,'AA',6666.66);     
insert into users(id,name,sal) values(111,'AAA',6666.66);     
insert into users(id,name,sal) values(1111,'AAAA',6666.66);     
insert into users(id,name,sal) values(99999,'AAAAA',6666.66);     
insert into users(id,name,sal) values(100000,'AAAAAA',6666.66); --错
--5表示最多存99999    

--(2)number(6,2):
insert into users(id,name,sal) values(2,'B',6.66);     
insert into users(id,name,sal) values(22,'BB',66.666);     
insert into users(id,name,sal) values(222,'BBB',666.6666);     
insert into users(id,name,sal) values(2222,'BBBB',6666.66666);     
insert into users(id,name,sal) values(22222,'BBBBB',66666.666666);--错 
--number(6,2)
--其中2表示最多显示2位小数,采用四舍五入,不足位数补0
--其中6表示小数+整数不多于6位
--其中整数位数不得多于4位,可以等于4位

--(3)varchar2(8):
insert into users(id,name,sal) values(1,'A',7777.77);     
insert into users(id,name,sal) values(2,'AA',7777.77);     
insert into users(id,name,sal) values(3,'AAA',7777.77);     
insert into users(id,name,sal) values(4,'AAAA',7777.77);  
insert into users(id,name,sal) values(5,'AAAAA',7777.77);  
insert into users(id,name,sal) values(6,'AAAAAA',7777.77);  
insert into users(id,name,sal) values(7,'AAAAAAA',7777.77);  
insert into users(id,name,sal) values(8,'AAAAAAAA',7777.77);  
insert into users(id,name,sal) values(9,'AAAAAAAAA',7777.77);--错

insert into users(id,name,sal) values(1,'哈',7777.77);     
insert into users(id,name,sal) values(2,'哈哈',7777.77);     
insert into users(id,name,sal) values(3,'哈哈哈',7777.77);     
insert into users(id,name,sal) values(4,'哈哈哈哈',7777.77);  
insert into users(id,name,sal) values(5,'哈哈哈哈哈',7777.77);--错  

--8表示字节
--GBK 哈 2字节

--(4)date:默认格式为:'07-2月-18'
--(5)CLOB【Character Large OBject】:大文本对象,即超过65565字节的数据对象,最多存储4G
--(6)BLOB【Binary Large OBject】:大二进制对象,即图片,音频,视频,最多存储4G

--为emp表增加image列,alter table 表名 add 列名 类型(宽度) 
alter table emp
add image blob;

--修改ename列的长度为20个字节,alter table 表名 modify 列名 类型(宽度) 
alter table emp
modify ename varchar2(20);

--删除image列,alter table 表名 drop column 列名
alter table emp
drop column image;

--重名列名ename为username,alter table 表名 rename column 原列名 to 新列名
alter table emp
rename column ename to username;

--将emp表重命名emps,rename 原表名 to 新表名
rename emp to emps;

--注意:修改表时,不会影响表中原有的数据

--笔试题:有【1000亿】条会员记录,如何用最高效的方式将薪水字段清零,其它字段内容不变?

--第一:从emp表中删除sal字段
      alter table emp 
      drop column sal;      

--第二:向emp表中添加sal字段,且内容默认0
      alter table emp
      add sal number(6) default 0;

--修改表不可回滚   

--创建表customers(单)和orders(多),使用primary key/not null/unique/default/foreign key约束
--要体现【on delete cascade/on delete set null】
--需求:删除客户,级联删除他所有的订单
      delete from customers where id = 1;
--需求:删除客户,不级联删除他所有的订单,只是将外健设置为NULL
      delete from customers where id = 1;   

create table customers(
  id number(3) primary key,
  name varchar2(4) not null unique
);
insert into customers(id,name) values(1,'A');
insert into customers(id,name) values(2,'B');

create table orders(
  id number(3) primary key,
  isbn varchar2(6) not null unique,
  price number(3) not null,
  cid number(3),
  --constraint cid_FK foreign key(cid) references customers(id) on delete cascade 
  constraint cid_FK foreign key(cid) references customers(id) on delete set null  
);
insert into orders(id,isbn,price,cid) values(1,'isbn10',10,1);
insert into orders(id,isbn,price,cid) values(2,'isbn20',20,1);
insert into orders(id,isbn,price,cid) values(3,'isbn30',30,2);
insert into orders(id,isbn,price,cid) values(4,'isbn40',40,2);

--创建表students,包括id,name,gender,salary字段,使用check约束【性别只能是男或女,薪水介于6000到8000之间】
create table students(
  id number(3) primary key,
  name varchar2(4) not null unique,
  gender varchar2(2) not null check ( gender in ('男','女') ),
  salary number(6) not null check ( salary between 6000 and 8000 )
);
insert into students(id,name,gender,salary) values(1,'哈哈','中',6000);--错
insert into students(id,name,gender,salary) values(2,'呵呵','男',5000);--错
insert into students(id,name,gender,salary) values(3,'嘻嘻','女',7000);--对

增删改数据

/*
SQL92/99标准的四大类
(1)DML(数据操纵语言):select,insert,update,delete
(2)DDL(数据定义语言):create table,alter table,drop table,truncate table
(3)DCL(数据控制语言):grant select any table to scott/revoke select any table from scott
(4)TCL(事务控制语言):commit,rollback,savepoint to 回滚点
*/
--创建新表xxx_emp,复制emp表中的结构,同时复制emp表的所有数据(再操作emp表之前先备份一份)
create table emps
as 
select * from emp;


--1、向emp表中插入一条记录(方式一:按表默认结构顺序)insert into 表名 values ...语法
insert into emp values(1111,'JACK','IT',7788,sysdate,1000,100,40);

--2、向emp表中插入一条记录(方式二:按自定义顺序)insert into 表名(列名) values ...语法
insert into emp(ENAME,EMPNO,JOB,MGR,HIREDATE,SAL,COMM,DEPTNO) 
values('MARRY',2222,'IT',7788,sysdate,1000,100,40);

--3、向emp表中插入NULL值(方式一:采用显示插入NULL值)
insert into emp values(3333,'SISI','IT',7788,sysdate,1000,NULL,40);

--4、向emp表中插入NULL值 (方式二:采用隐式插入NULL值),前提是所插入的字段允许插入NULL值
insert into emp(ENAME,EMPNO,JOB,MGR,HIREDATE,SAL,DEPTNO) 
values('SOSO',4444,'IT',7788,sysdate,1000,40);

--5、使用&占位符,动态输入值,&可以运用在任何一个DML语句中,在values子句中使用,例如:'&ename'和&sal
insert into emp values(&empno,'&ename','&job',&mgr,&hiredate,&sal,&comm,&xxxxxxxx);
--注意:&是sqlplus工具提供的占位符,如果是字符串或日期型要加''符,数值型无需加''符

--使用&占位符,动态输入值,&可以运用在任何一个DML语句中,在from子句中使用
select * from &table;

--使用&占位符,动态输入值,&可以运用在任何一个DML语句中,在select子句中使用
select empno,ename,&colname from emp;

--使用&占位符,动态输入值,&可以运用在任何一个DML语句中,在where子句中使用
select * from emp where sal > &money;

--使用&占位符,动态输入值,&可以运用在任何一个DML语句中,在group by 和 having子句中使用
select deptno,avg(sal)
from emp
group by &deptno
having avg(sal) > &money;

--6、删除emp表中的所有记录
delete from emp;

--7、将xxx_emp表中所有20号部门的员工,复制到emp表中,批量插入,insert into 表名 select ...语法
insert into emp
select * 
from xxx_emp
where deptno=20;

--8、将'SMITH'的工资增加20%
update emp set sal=sal*1.2 where ename = upper('smith');

--9、将'SMITH'的工资设置为20号部门的平均工资,这是一个条件未知的事物,优先考虑子查询
--第一:20号部门的平均工资
      select avg(sal) from emp where deptno=20;
--第二:将'SMITH'的工资设置为2207
      update emp set sal=2207 where ename = 'SMITH'; 
--子查询:
     update emp 
     set sal = (
    select avg(sal) 
        from emp 
        where deptno=20 
     ) 
     where ename = 'SMITH';   

--10、删除工资比所有部门平均工资都低的员工,这是一个条件未知的事物,优先考虑子查询
--第一:查询所有部门的平均工资
      select avg(sal) from emp group by deptno;
--第二:删除工资比(*,*,*)都低的员工
      delete from emp where sal<3000;
--子查询:
      delete 
      from emp 
      where sal < (
     select avg(sal) 
         from emp 
         group by deptno
      ); 

--11、删除无佣金的员工
delete from emp where comm is null;

/*
    修改完可以删除emp表,在通过xxx_emp恢复emp表
*/

--12、将emp截断,再自动创建emp表,truncate table 表名
truncate table emp;

--13、向emp表,批量插入来自xxx_emp表中部门号为20的员工信息,只包括empno,ename,job,sal字段
insert into emp(empno,ename,job,sal)
select empno,ename,job,sal 
from xxx_emp 
where deptno=20;

--14、依据xxx_emp表,只创建emp表,但不复制数据,且emp表只包括empno,ename字段
create table emp(empno,ename)
as
select empno,ename from xxx_emp where 1=2;

--15、向emp表(只含有empno和ename字段),批量插入xxx_emp表中部门号为20的员工信息
insert into emp(empno,ename)
select empno,ename from xxx_emp where deptno=20;
/*
drop table 和 truncate table 和 delete from 区别:
drop table
1)属于DDL
2)不可回滚
3)不可带where
4)表内容和结构删除
5)删除速度快

truncate table
1)属于DDL
2)不可回滚
3)不可带where
4)表内容删除
5)删除速度快

delete from
1)属于DML
2)可回滚
3)可带where
4)表结构在,表内容要看where执行的情况
5)删除速度慢,需要逐行删除
*/

事务

/*
什么是事务?
   事务是应用程序中一系列严密的操作,所有操作必须成功完成,否则在每个操作中所作的所有更改都会被撤消。也就是事务具有原子性,一个事务中的一系列的操作要么全部成功,要么一个都不做。 
   事务的结束有两种,当事务中的所有步骤全部成功执行时,事务提交。如果其中一个步骤失败,将发生回滚操作,撤消撤消之前到事务开始时的所以操作。 
例如:转帐

为什么要用事务?
如果不用事务的话,以转帐为例,可能出现一个用户钱增加了,另一个用户钱不变

事务的四个特征:
   事务具有四个特征:原子性( Atomicity )、一致性( Consistency )、隔离性( Isolation )和持续性( Durability )。这四个特性简称为 ACID 特性。 
1 、原子性 
事务是数据库的逻辑工作单位,事务中包含的各操作要么都做,要么都不做 
2 、一致性 
事务执行的结果必须是使数据库从一个一致性状态变到另一个一致性状态。因此当数据库只包含成功事务提交的结果时,就说数据库处于一致性状态。如果数据库系统运行中发生故障,有些事务尚未完成就被迫中断,这些未完成事务对数据库所做的修改有一部分已写入物理数据库,这时数据库就处于一种不正确的状态,或者说是不一致的状态。 
3 、隔离性 
一个事务的执行不能被其它事务干扰。即一个事务内部的操作及使用的数据对其它并发事务是隔离的,并发执行的各个事务之间不能互相干扰。 
4 、持续性 
也称永久性,指一个事务一旦提交,它对数据库中的数据的改变就应该是永久性的。接下来的其它操作或故障不应该对其执行结果有任何影响。 

编程中,事务可用于哪一层?
事务放在业务层

jdbc编程中,如何使用事务?
connection.setAutoCommit(false);
pstmt.executeUpdate();
connection.commit();
connection.rollback();

hibernate编程中,如何使用事务?
transaction.begin();
session.save(new User());
transaction.commit();
transaction.rollback();

spring编程中,如何使用事务?
spring可以分为二种
>编程式事务,藕合
>声明式事务,解藕,提倡
*/


--Oracle的事务只针对DML操作,即select/insert/update/delete

--MySQL的事务开始:start transaction
--Oracle的事务开始:第一条DML操作做为事务开始
/*
Oracle的提交事务
(1)显示提交:commit  
(2)隐藏提交:DDL/DCL/exit(sqlplus工具)
注意:提交是的从事务开始到事务提交中间的内容,提交到ORCL数据库中的DBF二进制文件

Oracle的回滚事务
(1)显示回滚:rollback
(2)隐藏回滚:关闭窗口(sqlplus工具),死机,掉电
注意:回滚到事务开始的地方

什么是回滚点?
在操作之间设置的一个标志位,用于将来回滚之用

为什么要设置回滚点?savepoint a;rollback to savepoint a;
如果没有设置回滚点的话,Oracle必须回滚到事务开始的地方,其间做的一个正确的操作也将撤销

使用savepoint 回滚点,设置回滚点a  
savepoint a;

使用rollback to savepoint,回滚到回滚点a处
rollback to savepoint a;

Oracle提交或回滚后,原来设置的回滚点还有效吗?
原回滚点无效了

Oracle之所以能回滚的原因是?
主要机制是实例池 
*/
/*
MySQL支持的四种事务隔离级别及能够解决的问题
(1read uncommitted -- 不能解决任何缺点
    读未提交,顾名思义,就是一个事务可以读取另一个未提交事务的数据。

    事例:老板要给程序员发工资,程序员的工资是3.6万/月。但是发工资时老板不小心按错了数字,按成3.9万/月,该钱已经打到程序员的户口,但是事务还没有提交,就在这时,程序员去查看自己这个月的工资,发现比往常多了3千元,以为涨工资了非常高兴。但是老板及时发现了不对,马上回滚差点就提交了的事务,将数字改成3.6万再提交。

    分析:实际程序员这个月的工资还是3.6万,但是程序员看到的是3.9万。他看到的是老板还没提交事务时的数据。这就是脏读。
(2read committed   -- 脏读,Oracle默认
    脏读是指在一个事务处理过程里读取了另一个未提交的事务中的数据。
    当一个事务正在多次修改某个数据,而在这个事务中这多次的修改都还未提交,这时一个并发的事务来访问该数据,就会造成两个事务得到的数据不一致。

(3)reapatable read  -- 不可重复读,脏读,MySQL默认
    不可重复读是指在对于数据库中的某个数据,一个事务范围内多次查询却返回了不同的数据值,这是由于在查询间隔,被另一个事务修改并提交了。
  例如事务T1在读取某一数据,而事务T2立马修改了这个数据并且提交事务给数据库,事务T1再次读取该数据就得到了不同的结果,发送了不可重复读

(4)serializable     -- 幻读,不可重复读,脏读,效率低
    幻读是事务非独立执行时发生的一种现象。例如事务T1对一个表中所有的行的某个数据项做了从“1”修改为“2”的操作,这时事务T2又对这个表中插入了一行数据项,而这个数据项的数值还是为“1”并且提交给数据库。而操作事务T1的用户如果再查看刚刚修改的数据,会发现还有一行没有修改,其实这行是从事务T2中添加的,就好像产生幻觉一样,这就是发生了幻读。

注意:jdbc/dbutils速度快,但书写烦
      mybaits速度中等,但书写"中等"
      hibernate速度慢,但书写"爽"

Oracle支持的二种事务隔离级别及能够解决的问题
Oracle支持:read committed 和 serializable

Oracle中设置事务隔离级别为serializable
set transaction isolation level serializable;

二个用户同时操作emp表,删除KING这条记录,会有什么后果?
因为有隔离级别的存在,所以不会出现二个用户都删除了KING这条记录,
一定是一个用户删除KING成功,在该用户没有提交的情况下,另一个用户等待
*/
发布了39 篇原创文章 · 获赞 157 · 访问量 9万+

猜你喜欢

转载自blog.csdn.net/qq_34417749/article/details/79278576