Oracle数据库教程笔记

视频链接地址:

https://www.bilibili.com/video/av53956941

数据库:数据的仓库
    以前存放数据:内存、文件
    内存: int num = 10 ;  问题:临时
    文件: 解析/操作起来麻烦

-》永久存放,方便解析/管理 ->数据库

主流的关系型数据库:
    oracle:产品免费,服务收费,强大稳定性 安全性
    mysql :MySQL AB开源, 2008被SUN收购, 2009年被Oracle收购; 版本:社区Community免费,企业版收费  ;产品免费,服务收费
    sql server:微软开发,强大的图形化工具,方便使用
    db2:IBM,多个操作系统、多个硬件


oracle版本:
    oracle8i/9i:internet ,开始走向网络
    oracle10g/11g:grid,网格计算,提高访问速度,避免舍近取远的问题
    oracle12c:cloud,云计算
    各个版本对于学习、研发 没有区别,只是在 最终的部署、运维时差异较大

oracle11g:目前主流


数据库服务器:将数据库部署在服务器上
oracle服务器
    1.基于关系型的数据库(RDBMS): oracle  mysql  sqlserver  db2....
        关系型->二维表
    
    非关系型:
        NoSQL:not only sql  ,redis/mongodb  :基于key-value结构   person.name 
    2.组成结构
        一个PGA对应于一个客户端:
    
    两阶段提交:
    pga->sga
    sg-a数据库(此阶段,会将一些重复/冗余的工作 进行合并,从而减少数据访问次数)

select *from 表名; 查询语句


基本概念:
    实体:java中的类
    记录:java的对象 (per(zs,23,170...)) ,行
    字段:java的属性,列
    表:同一个实体中,所有的记录、字段组合起来 就是一张表

                 
列的计算:
    select empno,ename ,sal ,sal*12 from emp;

SQL:
    什么控制行?什么控制列?

什么控制列?select empno,ename from emp ;

什么控制行?where

字符串/字符 、日期  : 单引号

大小写问题:
    a.命令/关键字:不敏感(不区别)
    b.数据:敏感(区分


运算符:
    操作运算符: + - / *  %
    关系运算符: > >= < <=     =    !=或<>
                如果是null,必须用is ,或is not
    逻辑运算福:  or  and  not
    
    select* from emp where not (mgr = 7788 and job = 'CLERK')


    select* from emp where mgr = 7788 and job = 'CLERK';
    where执行顺序:右->左


null:
    is/is not
    null的计算:
        任何数字 和null结算,结果为null  

    需要对null进行处理:null->0
        nvl:if
        nvl(comm,0 )

        nvl2:if...else
        nvl2(comm,comm,0)
                if(comm==null)  return 0
                else   return comm

对查询出的结果集去重:distinct
select distinct deptno from emp

连接符:         java: "hello"+"world"->"helloworld"
oracle:
    concat   ||

dual:oracle提供的 学习时使用 临时表:单行单列

select 'hello'||'world' from dual;


修改oracle默认的日期格式 
默认:DD-MON-RR
修改:
    alter session set NLS_DATE_FORMAT = 'yyyy-mm-dd' ;

    alter session set NLS_DATE_FORMAT = 'DD-MON-RR' ;


---
范围查询: 数字/日期
    between  小 and  大
>=小 and  <=大

    

模糊查询:
    like
        配合通配符使用:_  :一个字符    
                %  :任意个字符

    ename like ..
    数字、日期:like

    姓名中第二个字母是M的员工信息:
        select *from emp where ename like  '_M%' ;
    
    姓名中包含M的员工信息:
        select *from emp where ename like  '%M%' ;
    姓名长度>6的员工信息:   >6  >=7
    select *from emp where ename like  '_______%' ;

    姓名中包含下划线的 
    zhang_san
    select *from emp where ename  like '%\_%'  escape '\' ;  

    not  in 不能出现null:如果出现了null,结果为null
    select *from emp where deptno not in(10,20,30,null) ;
    

select *from emp where deptno not in(10,20,30,null) ;

select *from emp where deptno  != 10 and deptno  != 20 and deptno  != 30 and deptno  != null 


select *from emp where mgr not in
(select mgr from emp);


排序:
    order by 字段名|表达式|序号
select *from emp order by sal desc ;

select *from emp order by sal asc ;默认

select *from emp order by sal+10000 desc ;
null默认是最大值 


多列排序 :
sal, hirdate


函数:
    单行函数:一次操作一行
    多行函数 :以此操作多行

单行函数: 字符函数  数值函数  日期函数  转换函数 通用函数

字符函数 : lower   upper  initcap


 dual :单行单列  ->单行

substr(str,begin,len)  :从1开始数

length字符数 / lengthb 字节数

英文/数字

如果中文/符号: 
    utf-8编码格式下: 一个汉字/符号 占3个字节
    gbk:  一个汉字/符号 占2个字节

查看当前系统编码格式:
    select * from nls_database_parameters ;

insrt(str,substr) 

lpad/rpad:填充

trim:去掉任意字符

replace


数值函数:
    round(数字,n位数):四舍五入  ,保留n位小数
    trunc(数字,n位数):舍尾,保留n位小数

mod()


日期:
    sysdate:当前时间
    格式化: 日期-》字符


    to_char(日期,格式)
    

    日期+-数字  (默认是天)

    日期 - 日期 


    计算员工工龄 :入职日期 天 星期 月 年
select ename ,hiredate , (sysdate - hiredate) , (sysdate - hiredate)/7 , (sysdate - hiredate)/30, (sysdate - hiredate)/365 from emp;


months_between(日期1,日期2) : 日期1-日期2


add_months(日期,月数):
当前最大是第几天 last_day

下一个星期n是哪一天next_day
select next_day(sysdate,'星期五') from dual ;


round
trunc
if
else if
else if.
...
else

    通用函数 :
    a. nvl/nvl2
    b. nullif(a,b)  :a=b,null ,否则返回
    c coalesce :从左往后 找到第一个不为null的值
    d.条件判断函数
    decode(字段,条件1,返回值1,条件2,返回2,....,最后表达式)
select ename,job , sal 涨前,  decode(job, 'PRESIDENT',sal+1000,'MANAGER',sal+500,sal+300) 涨后 FROM EMP;

    case表达式
    select ename ,job ,sal  涨前,case job 
    when  'PRESIDENT' then sal+1000
    when  'MANAGER' then sal+500
    else  sal + 300 end
       涨后 
    from emp ; 
    

case 
    when   ... then
    when  ... then
    else
end ;

    转换函数:
        隐式转换/显式转换

隐式转换:    
字符-数字
数字-字符
字符-日期
日期-字符


显式转换:
字符->字数
select to_number('¥123,456.7',  'L999,999.9') from dual ;
    
字数->字符

字符-日期

日期-字符
to_char


多行函数:组函数、 聚合函数
    count(*) ->  19


求有几个部门
count() 自动排除null
    max/min/avg/sum


分组:
    各个部门总工资: 对部门分组 dept  10   20  30   40
select deptno,avg(sal) from emp 【group by deptno】 ;

select deptno,ename , avg(sal) from emp group by deptno ;

10  8000
20    6000
30    5000
40    9000

分组查询时,不在组函数(多行函数)中的列,必须在group by中。


先根据部门分组 ,再根据job分组

--各个部门中各个工作 的平均工资
select deptno,job,avg(sal) from emp group by deptno ,job ;

对行筛选用where


对组进行筛选用Having

可以在Having使用多行函数count  min  avg
但是 不能在where中使用多行函数


多表连接查询:
    1.交叉连接(笛卡尔积):所有情况的组合 ,不推荐使用
select * from emp  ,dept  ;


    2.内连接 :多张表通过  相同字段进行匹配,只显示匹配成功的数据
    a.
        select * from emp e ,dept d
        where e.deptno = d.deptno ;
    b.
        select * from emp e
        inner join dept d
        on e.deptno = d.deptno 
    不等值连接(一般不用)
    select * from emp e ,dept d
        where e.deptno <= d.deptno ;
    
    3.外连接
    左外连接:以左表为基准(左表数据全部显示),去匹配右表数据,如果匹配成功 则全部显示;匹配不成功,显示部分(无数据部分 用NULL填充)
    a.(oracle独有)
        select * from emp e ,dept d
        where e.deptno = d.deptno(+) ;


    b
        select * from emp e
        left outer join dept d
        on e.deptno = d.deptno 


    右外连接
    右外连接:以右表为基准(右表数据全部显示),去匹配左表数据,如果匹配成功 则全部显示;匹配不成功,显示部分(无数据部分 用NULL填充)
    a.(oracle独有)
        select * from emp e ,dept d
        where e.deptno(+) = d.deptno;


    b
        select * from emp e
        right outer join dept d
        on e.deptno = d.deptno 


    全外连接 = 左外 + 右外连接 - 去重


    自连接:将一张表 通过别名 “视为”不同的表


    查询 员工姓名,以及 该员工的领导姓名
    select e.ename ,b.ename from emp e,emp b
    where e.mgr =b.empno;
    //员工表的领导编号mgr = 领导表的 员工编号号empno


    自连接 必须费性能:  emp -> e,b 

优化?
层次连接:
    select level ,empno, ename ,mgr from emp 
    connect by prior  empno=mgr
    start with mgr is null
    order by level ;
    

---
子查询
    比SCOTT工资高的 员工信息
    1:scott的工资->5200
    select SAL from emp where ename = 'SCOTT' ;

    2.>5200的员工信息
    select *from emp where sal >  ;
->合二为一
    
    select *from emp  where sal > (select SAL from emp where ename = 'SCOTT' )

    ①子查询可以出现的位置:where、select、having、from ;不能写在group by 后面。
    where
    select: 单行列 (常量列)
        select empno 第一列,ename 第二列,(select job from emp where empno =7369) 第三列 from emp ;
    having:
    查询最低工资比10号部门的最低工资高的部门编号。

分组
select deptno,min(sal) from emp  
group by deptno
having min(sal) > ( select min(sal) from emp where deptno =10  );

    from:相当于修改了表结构
    select * from emp;
    select * from  ( select empno,ename, sal*12 from emp) ;
    

    ②主查询和子查询 可以是,也可以不同同一张表

    查询销售部的员工信息
    1.现根据“销售部”查询 销售部的部门编号30
    select deptno from dept where dname = 'DNAME' ;
    2.根据部门编号30 查询员工信息
    select * from emp where deptno = (select deptno from dept where dname = 'SALES' );

    ③子查询可以使用 单行操作符(=,<),多行操作符(in)
    查询工资比30号部门中 任意其中一个员工高的(存在) 员工信息    

    "只需要满足一个即可,存在一个就可以"->any
    select *from emp where sal > any(select sal from emp) ;

    select *from emp where sal > (select min(sal) from emp) ;


    查询工资比30号部门中 全部员工高的(存在) 员工信息    
        “所有、全部”->all
    select *from emp where sal > all(select sal from emp) ;
    select *from emp where sal > (select max(sal) from emp) ;

    多行操作符:
    查询销售部,财务部的员工信息
select * from emp where deptno in
(select deptno from dept where dname = 'SALES' or dname='ACCOUNTING');

any:只要有一个  
all:全部

    ④子查询中的null :子查询的结果中不要有NULL!!
select *from emp where mgr in (7566,7698);
select *from emp where mgr in (7566,7698,NULL);

in : = or = or 
select *from emp where mgr =7566 or mgr=7698 or mgr = NULL;

select *from emp where mgr not in (7566,7698,NULL);


select *from emp where mgr not in (7566,7698,NULL);


select *from emp where mgr not in (7566,7698,NULL);

select *from emp where   mgr !=7566 and mgr!=7698 and mgr != NULL ;


NULL:自身特性: 如果!=NULL则无法查询出任何数据 


is  null
is not null 

=null
!= null

    查询 不是领导的员工信息(子查询时排除NULL)

不是领导:判断empno 是否存在于mgr中
select * from emp 
where empno not in (select mgr from emp where mgr is not null )

    ⑤一般不在子查询中排序,除非TOP-N问题(分页)


集合运算细节:
        各个集合的列数、类型必须保持一致
select empno ,ename from emp
union
select deptno,job from emp;


--报表
    查询总工资、各个部门的共工资、各个部门中各个工作的总工资

各个部门中各个工作:
    
    select deptno,job,sum(sal)   from emp group by deptno,job ;

10    sales    7000
10    dev    8000
20    xxx    6500

各个部门的共工资、
    select deptno,sum(sal)   from emp group by deptno ;

总工资

    select sum(sal)   from emp ;

NULL:常量列
select deptno,job ,sum(sal)   from emp group by deptno,job 
union
select deptno, NULL ,sum(sal)   from emp group by deptno 
union
select   NULL,NULL ,sum(sal)   from emp ;


增强group by:rollup()

select deptno,job ,sum(sal)   from emp group by rollup( deptno,job) ;


group by  rollup( a,b)相当于:
        group by a,b    
        group by a,
        group by null 


---
SQL语句的类型:
DQL:数据查询语言select
DML:数据操作语言,insert delete update   --》可以回退(可以进行事务操作)
DDL :数据定义语言  create/drop /truncate /alter table
DCL:数据控制语言  grant, revoke


DML:
增加数据insert
insert into 表名(字段名1,字段名2,...,) values(字段值1,字段值2,...)

字段名和字段值一一对象:数据类型、个数、顺序


insert into emp(EMPNO,ENAME,JOB,MGR,HIREDATE,SAL,COMM,DEPTNO)
values(2222,'zhangsan','MANAGER',7788,'19-9月 -88',9998,1000,10);

可以省略字段名:
1.values插入的数据  必须是 完整的字段,并且顺序和默认顺序一致
2.目前使用的SQL99标准,可以省略字段名(如果是SQL92则不能省略,MyCat)
insert into emp
values(3322,'LISI','MANAGER',7788,'19-9月 -88',9998,1000,10);


如果插入的数据不完整,可以协商 部分字段名
insert into emp(EMPNO,ENAME,JOB)
values(444,'zhan','MANAGER');

动态输入插入的值(&)  Scanner input = new Scanner(System.in);  input.next();


insert into emp(EMPNO,ENAME,JOB)
values(&empno,&xxx,&job);
如果是字符、日期: 仍然需要加'   '

insert into emp(EMPNO,ENAME,&otherName)
values('5555','kkk',&otherValue);


--
批量插入数据
    1.创建新表(批量插入之前不存在)
    emp ->复制 mytab

    create table mytab 
    as
    select *from emp;


create table mytab2
as
select empno,ename ,job from emp;


create table mytab3
as
select empno,ename ,job from emp
where sal < 6000;
    
    还可以用于快速创建表结构:
    mytab4 -> emp 

    create table mytab4 
    as
    select *from emp where 1=0 ;

    2.在旧表中插入(已存在的表)
        insert into mytab4(empno,ename,sal)
        select empno,ename ,sal from emp;

    3. begin ...end  / 

begin
    insert into emp
values(1221,'LISI','MANAGER',7788,'19-9月 -88',9998,1000,10);
    insert into emp
values(1223,'LISI','MANAGER',7788,'19-9月 -88',9998,1000,10);
end ;


    海量数据: 数据泵 \  SQL Loader\ 外部表

---
删除delete
delete from 表名 ;
delete from emp  where     empno >7900;
    1.加where
    2. delete  from 表名 ;

全表删除:
1.    delete from emp  ; 可以回退
    truncate table emp  ;不能回退
        原因: DML:insert  update  delete  ->可以回退
        
2.测试二者执行时间    
    打开执行时间:
    set timing on/off
对于少量数据: delete 效率高  ,一行一行删除
对于海量数据:truncate效率高 ,  a.drop table 丢弃整张表 ,b.重新创建表

3.delete支持闪回, truncate不支持闪回
4.delete不会释放空间 (换两个地方存储数据[undo空间]),trucante会
5.delete会产生碎片,trunate不会
    如果碎片太多,需要整理碎片:a.  alter table 表名 move ;  b.导出导入


---

update/delete :where
修改update


update 表名 set 字段名1=字段名1  , 字段名2=字段名2,字段名3=字段名3...  where ...

update emp set ename = 'x' ,job ='y'  where empno>7900;

        

--DDL: create/drop/truncate/alter
创建表
 create table mytab6 
(
   id  number ,
   name varchar(10),
   age number
)
;
注意事项:
    1.权限和空间问题
    2.表名的规定:
    a.必须以字母开头
    b.表名只能包含: 大小写字母、数字、_、$、#
    c.长度  1-30个字符
    d.不能与数据库中其他对象重名(表,视图、索引、触发器、存储过程....)
    e.不能与 保留字重名
    查看保留字:DBA账户
    sqlplus / as sysdba
    查看保留字:
        select *from v$reserved_words order by keyword asc ;

    设置某个字段的宽度:
    字符
        col KEYWORD for a10
    数字
    col  LENGTH for 9999

修改表:
    a.追加新列

    alter table mytab6 add myother varchar2(10) ;

    b.修改列
        修改列的长度
            alter table mytab6 modify  myother varchar2(20) ;
        修改列的类型

            alter table mytab6 modify  myother number ;
        注意: blob/clob不能修改  ->先删除此列,重新追加

            alter table mytab6 add myother2 blob ;

            alter table mytab6 modify  myother2 number ;

    c删除列
        alter table mytab6 drop column myother2 ;

    d重命名列
    alter table mytab6 rename column myother to myother3 ;

删除表
    select *from tab; 表以及回收站中的表
    drop table mytab6;  -->放在了回收站
    查看回收站        
    show recyclebin;

    清空回收站
        purge recyclebin;
    
    还原回收站
        闪回

删除表 并清空: drop table test02 purge ;


===========================================================================
===========================================================================


rownum/rowid:删除重复数据


create table mystudent(
stuno number,
stuname varchar2(10),
stuage number 
);

insert into mystudent values(1,'zs',23) ;
insert into mystudent values(1,'zs',23) ;

insert into mystudent values(2,'ls',24) ;
insert into mystudent values(2,'ls',24) ;

insert into mystudent values(3,'ww',25) ;
insert into mystudent values(3,'ww',25) ;

insert into mystudent values(4,'zl',26) ;


delete from mystudent where stuno in(
select distinct stuno from mystudent);

去重:distinct


rowid:根据插入的顺序 依次递增


rownum:逻辑伪列

rowid:物理伪列,18位:
    前6位: 数据对象编号
    依次往后数3位:数据文件编号
    依次往后数6位:数据块编号
    依次往后数3:行号
思路:
    根据编号分组(将重复的数据 放到一组) ,然后在每组中只保留一个

保留:rowid最小的
delete from mystudent where  rowid not in (select min(rowid) from mystudent  group by stuno );


约束
    对数据的限制条件:  数据类型

常见6个约束:
    检查约束(check)           name > 4 
    唯一约束(Unique)          id:1  2  3 4  null 
    主键约束(Primary key)     类似唯一约束(唯一) 
    外键约束(Foreign Key)      两张表 学生表   课程表(1 2 3)
    非空约束(Not null)          不能为null
    默认约束(Default)         adress:   西安
                insert into student(id,name) values(1,'zs')

主键和唯一的区别:
    a.【主键不能为Null】,唯一 可以为null
    b.主键可以是复合主键,也可以是单值主键(id)
    c.一张表中 只能设置一次主键(复合主键),但唯一键可以设置多次


1    zs    bj     hd
2    ks
3    zs      bj       xc

分类:
列级约束         表级约束
作用于一个列         作用于一个列/多列
列的后面            表的后面
可以有多个约束(空格)   逗号,
全部的6个        4个(主键 外键  唯一 检查)

列级约束:
create table student(
 stuno number(3) primary key  ,
 stuname varchar2(10) not null unique ,
 stuaddress varchar2(20) default '陕西西安' check(length(stuaddress)>2),
 stubid number(3)
);


主键:  非空+唯一
insert into student values(1, 'zs','h北京',2) ;
insert into student values(2, 'zs1','h北京',2) ;

insert into student values(3, 'zs1','x北京',3) ;

insert into student values(4, null,'y北京',4) ;

insert into student values(5, 'xx','北京',5) ;
-default代表使用 默认约束的值
insert into student values(5, 'xx', default ,5) ;

注意事项:
    a.报错:违反唯一约束条件 可能主键报错 也可能唯一约束报错
    b.如果有多个约束,default必须放在第一位
    c.check约束: 如何编写 :和使用where完全相同
    d.唯一约束: 可以是Null,但不适用于Null(可以有多个null)


create table student(
 stuno number(3) primary key  ,
 stuname varchar2(10) unique  ,
 stuaddress varchar2(20)  default '陕西西安' check(length(stuaddress)>2) ,
 stubid number(3)
);


insert into student values(2, null,default,1) ;


insert into student values(3, null,default,1) ;


约束命名
    规范:约束类型_字段名
主键:    PK_stuno
检查约束:  CK_字段名
唯一约束: UQ_字段名
非空约束:  NN_字段名
外键约束:  FK_子表_父表
默认约束: 一般不需要命名

加约束名: constraint 约束名  

create table student(
 stuno number(3) constraint PK_stuno    primary key  ,
 stuname varchar2(10) constraint NN_stuname  not null  constraint  UQ_stuname  unique ,
 stuaddress varchar2(20) default '陕西西安' constraint CK_stuaddress  check(length(stuaddress)>2),
 stubid number(3)
);


insert into student values(1, 'zzz',default,1) ;

注意事项:
    约束名是 多个表公用的 (多个表中的约束 不能重名)


create table student2(
 id number(3) constraint PK_stuno    primary key  ,
 name varchar2(10)
);


表级约束

create table student2(
 stuno number(3) ,
 stuname varchar2(10)  ,
 stuaddress varchar2(20) ,
 stubid number(3),
  constraint PK_sno primary key(stuno) ,
  constraint UQ_sname_subid unique(stuname,stubid),
  constraint CK_saddress check( length(stuAddress)>2)
);

外键

create table student3(
 stuno number(3) ,
 stuname varchar2(10)  ,
 stuaddress varchar2(20) ,
 subid number(3)   
);


insert into student3(stuno,stuname,subid) values(1,'zs',1);
insert into student3(stuno,stuname,subid) values(2,'ls',1);
insert into student3(stuno,stuname,subid) values(3,'ww',2);

create table sub
(
    sid  number(3),
    sname   varchar2(10)
);


insert into sub values(1,'java');
insert into sub values(2,'python');


尝试插入非法数据:
insert into student3(stuno,stuname,subid) values(4,'zl',3);


给表加外键:
    创建表的同时 增加外键
drop table student3 ;


create table student3(
 stuno number(3) ,
 stuname varchar2(10)  ,
 stuaddress varchar2(20) ,
 subid number(3)  ,
 constraint FK_student3_sub foreign key(subid) references sub(sid) 
);

其中,解释: constraint FK_student3_sub foreign key(subid) references sub(sid) ;

直接创建外建时报错:此列列表的【唯一关键字或主键】不匹配 ,含义是:外键所指向的 字段 必须先是 主键 或者唯一约束的键。


定义外键 需要4个参数:  两个表名 ,两个字段名

insert into student3(stuno,stuname,subid) values(1,'zs',1);
insert into student3(stuno,stuname,subid) values(2,'ls',1);
insert into student3(stuno,stuname,subid) values(3,'ww',2);


drop table sub;

create table sub
(
    sid  number(3) unique,
    sname   varchar2(10)
);
insert into sub values(1,'java');
insert into sub values(2,'python');


insert into student3(stuno,stuname,subid) values(1,'zs',1);
insert into student3(stuno,stuname,subid) values(2,'ls',1);
insert into student3(stuno,stuname,subid) values(3,'ww',2);
insert into student3(stuno,stuname,subid) values(4,'zl',3);

外键含义:  A.a ->B.b字段,  a中的数据 必须来自于b中。   

如果删除父表中  外键所指向的列, 2个策略:级联删除|级联置空


drop table student3;
create table student3(
 stuno number(3) ,
 stuname varchar2(10)  ,
 stuaddress varchar2(20) ,
 subid number(3)  ,
 constraint FK_student3_sub foreign key(subid) references sub(sid)  on delete cascade【或set null 】
);

insert into student3(stuno,stuname,subid) values(1,'zs',1);
insert into student3(stuno,stuname,subid) values(2,'ls',1);
insert into student3(stuno,stuname,subid) values(3,'ww',2);

级联删除
drop table student3;
create table student3(
 stuno number(3) ,
 stuname varchar2(10)  ,
 stuaddress varchar2(20) ,
 subid number(3)  ,
 constraint FK_student3_sub foreign key(subid) references sub(sid)  on delete cascade
);


--
级联置空
drop table student3;
create table student3(
 stuno number(3) ,
 stuname varchar2(10)  ,
 stuaddress varchar2(20) ,
 subid number(3)  ,
 constraint FK_student3_sub foreign key(subid) references sub(sid)  on delete set null 
);
insert into student3(stuno,stuname,subid) values(1,'zs',1);
insert into student3(stuno,stuname,subid) values(2,'ls',1);

级联删除:当删除父表中的数据时,子表 会跟着删除相对应的数据;
级联置空:当删除父表中的数据时,子表 会将 相对应的 那一字段的值设置为Null,其他字段不影响;


外键使用建议:
    1.当父表中没有相对应数据时,不要向子表增加数据(如果sub表没有编号为2的课程,那么子表student不要去选择2号课程)
    2.不要更改父表的数据,导致子表孤立
    3.建议:在创建外键时  直接设置成 级联删除 或级联置空
    4.删除表? 先删除子表,再删除父表

追加约束:在创建表示忘了加约束,后续可以追加约束

1.唯一、主键、检查、外键约束
alter table 表名 add constraint 约束名  约束类型I


create table student4(
 stuno number(3) ,
 stuname varchar2(10)  ,
 stuaddress varchar2(20) ,
 subid number(3) 
);
alter table student4 add constraint UQ_stuaddress4  unique(stuaddress);
alter table student4 add constraint PK_stuno4  primary key (stuno );

alter table student4 add constraint CK_stuname4  check(length(stuname)>2);

alter table student4 add constraint FK_student4_sub   foreign key(subid) references sub(sid);


不适用于 默认、非空
alter table student4 add constraint NN_stuname  not null(stuname);
alter table student4 add constraint DF_stuname  default 'hello' ;


2. 默认、非空
    
alter table 表名 motidy  字段名 constraint 约束名  约束类型

非空
 
alter table student4  modify  stuname constraint NN_stuname4  not null ;

默认(建议默认约束不起名字,不写constraint)
alter table student4  modify  stuname  default '没名字'   ;


删除约束:
    alter table 表名  drop constraint 约束名;
alter table student4  drop constraint UQ_stuaddress4;
alter table student4  drop constraint PK_stuno4;
alter table student4  drop constraint CK_stuname4;
alter table student4  drop constraint FK_student4_sub;
alter table student4  drop constraint NN_stuname4;

    特殊情况: 
        默认约束(删除默认约束: 将默认约束置为null)
    alter table student4  modify  stuname  default null   ;

--
完整性约束:保证数据的正确性、相容性、防止数据冗余等。
    域完整性: 列。数据类型,非空约束,检查约束,外键约束

    实体完整性:行。主键约束、唯一约束

    引用完整性:不同表之间。外键

    自定义完整性:触发器(当执行换一个操作时,会自动触发另一个操作)。例如:自定义需求 学生的上学时间 必须在出生日期之后。

三大范式NF
    1NF:确保每列的原子性(不可再分)
student
    id    name    address
    1    zs    陕西省西安市长安区
    拆:
    id    name    province   city  zone

    2NF:
        宏观:每张表只描述一件事情(例如,一个student表 描述的全部是学生字段)

赖于 :A->B,  
        换种说法:“决定”的反义词, B->A  
        微观:通过2NF定义:除了主键以外的其他字段,都依赖于主键

a,b,c,d,e  

    3NF:
        
        微观:除了主键以外的其他字段,都不传递依赖于主键
A->B
B->决定于A

X->Y->Z: X传递决定了Z;   Z传递依赖于X

a,    b,        ,d    ,    e  

    
100    :  100   a->  b->  c 
100- >多张表?


    注意:
        要么满足第N范式,必须先满足第N-1范式。
        三大范式 可以帮助我们 规范数据的设计,好处是 防止数据混乱、数据冗余(重复)
        缺点: 很难严格排除出所有不满足的表,并且  难以拆分   ;会一定程度影响性能
    x->拆?


a
select  ..from a;


a-a+b+c

select  ..a,b,c   where 关联查询  ,多表查询 会比单表查询更加 消耗性能。

        建议:三大范式 只是一个建议,不必严格遵守。
    实际使用时,需要“规范性”和“易用性、性能”间综合考虑

    


数据库设计软件:
    Power Designer


General:表名
name:给用户看的,只是用于显示
code:代码实际操作的


在PD设计完毕后,可以自动生成代码:ctrl+G

视图 : 属于数据库对象之一
    表、视图、序列、索引、同义词、触发器

    视图,是一个虚表。建立在表的基础之上
    注意:一张表,或多张表


创建视图的语法:

create  view 视图名
as 
    select ...语句
    

好处:
    a.简化查询
原始SQL:
select *from X  ,Y where X.x = Y.y ;
select *from emp e  ,dept d where e.deptno = d.deptno;

select d.deptno 部门编号,e.empno,e.ename,e.sal,e.comm ,d.dname from emp e ,dept d   where  e.deptno =d.deptno and  d.deptno=20;

用视图封装以上的查询结果:
create  view  myempview
as 
    select d.deptno 部门编号,e.empno,e.ename,e.sal,e.comm ,d.dname from emp e ,dept d where e.deptno=d.deptno and  d.deptno=20; 

用视图简化查询:
select * from myempview ;
    b.增加数据的安全性。可以将 其他开发人员 需要的某些字段 封装到一个视图中 交付


操作视图: DML  +Query  和表完全一致

注意:
    某个用户在创建视图时,可能权限不足。需要授权。
    如果在创建视图时,给某个字段起了别名,那么在视图中 就只能识别 该“别名”而不能识别原来真实的字段名。

emp    20        ->  empview(a1,b1,c1)

通过sys 授予scott 创建视图的权限。
    撤销revoke create view  from scott;
    创建grant  xxxx to scott

尝试修改视图时:update myempview set ename = 'hello' where  empno=7934 ;
报错:无法修改与非键值保存表对应的列

本次的原因:在二表关联时,忘了编写 连接条件
select d.deptno 部门编号,e.empno,e.ename,e.sal,e.comm ,d.dname from emp e ,dept d   where  【e.deptno =d.deptno】 and  d.deptno=20;

根本原因:在oracle中,如果是更新操作是 针对单表,可以批量更新。update  xxx set xx =xx where ;

但如果是 “多张表联合更新” ,则必须明确,不能出现歧义;
update ..emp \dept

update myempview ;

单表 可以任意更新 ;     一次性更新多张表,则必须唯一;


update myempview set ename = 'hello' where  empno=7934 ;

注意: 修改的视图(DML),会影响原表。一般建议  对视图 仅仅进行查询操作,不要进行DML.


建议:    如果update操作涉及了多张表,则很容易出现 异常;因此建议,update只对单表进行操作。


drop  view myempview ;

create view myempview
as
   select empno ,ename ,deptno from emp where deptno =20 ;

视图选项a.
create view 视图名
as
 select 语句..
  with check option ;


 with check option :限制对视图操作时,必须满足where子句


drop  view myempview ;

create view myempview
as
   select empno ,ename ,deptno from emp where deptno =20   with check option;


b.强烈建议
with read only ;

视图只建议查看,不建议DML。因为对视图的操作,会影响原表。

create view myempview
as
   select empno ,ename ,deptno from emp where deptno =20   with read only ;


        简单视图                复杂视图

表的数量        1                1/n
函数        没有                有
分组        没有                有

create view xx
as 
select  sal+1000   from 一张表... group by  ..

b.如果非要对视图进行增删改,还需要遵循一些严格的苛刻条件。
    ①当视图中存在以下之一时,不能Insert/update
        group by 、distinct、组函数、列的定义为表达式

    ②当视图中存在以下之一时, 不能delete
      
        group by 、distinct、rownum伪劣

-->视图只查看,不要DML


oracle 文字录屏
开启 spool  e:\note.txt 

sql.....

关闭spool  off;

事务
    概念:作为单个逻辑工作单元执行的一系列操作
    四大特性:ACID

转账:
    zs->ls
    1000

:update  :   zs -1000
         ls +1000

    Atomicity原子性:要么都成功,要么都失败。


    Consistency:一致性 :事务执行前后 ,总量保持一致


    Isolation隔离性:各个事务并发执行时,彼此独立

    Durability:持久性:持久化操作。


事务的生命周期:
    (MySQL: 自动提交,自动将每一条DML语句直接commit )
Oracle:手工提交
    事务的开始标识:  第一条DML
          事务的中间过程: 各种DML操作
    结束:
        a.提交
            i.显示提交:commit
            ii.隐式提交(自动提交):正常退出exit(ctrl+c)、DCL(grant ....to..., revoke ..from )、DDL(create ... ,drop ....)

    
        b.回滚
            i.显示回滚:rollback
            ii.隐式回滚:异常退出(宕机、断电)

保存点savepoint:
    打游戏:  10   :  1 ,2(savepoint)  , 3,4,5 (savepoint) ,6,7,8  -->rollback

    语法:  x a b    savepoint  保存点名字

 insert into xx values(1,'zs');
 insert into xx values(2,'ls');  

savepoint initdate ;

insert into xx values(3,'ww');
 
rollback to savepoint initdate  ;

事务的隔离级别:
        多个事务会产生很多并发问题:
        1.脏读:当一个事务正在访问数据,并对此数据进行了修改(1->2),但是这种修改【还没有提交到数据库(commit)】; 此时,另一个事务也在访问这个数据 。本质: 某个事务(客户端)读取到的数据是 过时的。
        2.不可重复读: 在一个事务内(客户端)内,多次读取同一个数据,但结果不同。
            本质:就是事务A拿到了 被其他事务B修改并提交后的数据 


        3.幻读(虚读):在一个事务内(客户端)内,多次读取同一批数据,但结果不同。


    不可重复读和幻读的区别:
        a.不可重复读指的是对于“同一条”数据的查询操作  a ->b
         幻读对于“多条数据”的查询操作,数据量数:  20条 -> 18条  
        b.不可重复读:update
          幻读:insert|delete 


四种隔离级别的程度 依次递进(解决 并发的效果,越来越 稳定) ,但是性能越来越低。
    并发性 、可用性 本身就是矛盾的。 


Oracle只支持其中两种:Read Committed(默认),Serializable  
(oracle自身扩种了一种 read only,实际 read only隶属于 Serializable级别 )

切换四种隔离级别:
    set transaction isolation level Serializable;


切换read only:
set transaction  read only ;

MySQL 支持全部的四种

===========================================================================
===========================================================================


序列:模拟自增

本质就是内存中的数组  (20)
[1,2,3,...,20] [21,22,...,40]
create sequence 序列名
increment by 步长
start with 起始值
maxvalue | nomaxvalue
minvalue | nominvalue
cycle | nocycle
cache n | no cache ;

查看序列
select *from user_sequences ;


create sequence myseq;

序列有2个属性:
nextval:下一个值
currval:当前值
    
    1    2    3    4    5    ....
*

序列会接着上一次的值 继续使用。


insert into person values(myseq.nextval, 'ls4');
insert into person values(myseq.nextval, 'ws4');
insert into person values(myseq.nextval, 'zs4');


create sequence myseq1
increment by 2
start with 1000;

create sequence myseq2
increment by 2
start with 1
maxvalue 9
minvalue 1
cycle 
cache 3  ;

[1    3    5]    7    9
cache元素的个数 <= 循环元素个数


insert into person values(myseq2.nextval, 'xx');
循环序列 不能用于给 主键/唯一约束的键 赋值


裂缝: [1,2,3...,20] [21,]
断电、异常、回滚、多表使用同一个序列 ……

1 2 3 4 5 

A  1 2 4
B  3 

修改:只对修改之后的 操作有效
alter sequence myseq
increment by 2
;


删除序列 drop sequence 序列名 ;

 drop sequence myseq2;

索引:
  类似于书的目录
    索引类型 默认B树索引(默认)、位图索引


create 类型 名字

create index 索引名

create index myindex  on emp(deptno) ;
主键默认 就是索引


create index myindex  on emp(deptno ,sal   ) ;


什么时候 适合建立索引:
    数据集中的列,经常在where中使用的列, 数据量大
        数据集中的列:主键列(empno,id)不集中,但是因为 会被频繁使用 ,因此也适合建索引

empno :
    1
    2    
    3

empno,ename ,job,sal......20


select *from emp where age = 23 ;

字段:字典


deptno :
1000   -> 10


empno :
    1
    2
    3

删除索引
drop index 索引名
drop index myindex ;


同义词(别名)

数据库对象(表 视图 索引...)起别名 (默认私有/专用)


hr :employees;

 查看其它用户的表,报错“表或视图不存在”:可能是权限不足

授权:
grant xxx  to 用户名;
    grant select on hr.employees  to scott;

select count(*) from hr.employees ;

起别名:select count(*) from hremp ;

grant create synonym to scott ;

    create synonym  hremp for hr.employees ;

revoke xxx from 用户名;


创建公有同义词
    
    create public synonym  hremp2 for hr.employees ;

公有同义词的操作(创建、删除) 一般建议由管理员操作。。


drop [public ] sysnonym 同义词名


PLSQL:可以对SQL进行编程

开发工具
    plsql developer
    oracle sql developer

plsql:
declare
    变量、常量、光标(游标)、例外(自定义异常)
begin
    ...
    exception 
        ...
end ;

示例
set serveroutput on ;
declare
    --变量、常量、光标(游标)、例外(自定义异常)
    psex char(3) := '男' ;
    pname varchar2(10) ;
begin
    
    select ename into pname from emp where empno =7499 ;
    dbms_output.put_line('hello world:' || psex ||'---' || pname);
    
end ;

pname emp.ename%type ;--引用型变量,推荐


记录型变量:java 对象,可以用于同时保存多个变量值

java 对象
Person per = new Person(1,'zs',28,11...,...);
per.name

示例
set serveroutput on ;
declare
    --变量、常量、光标(游标)、例外(自定义异常)
   emp_info emp%rowtype ;
    
begin
        select * into  emp_info from   emp where empno =7788;
   
        dbms_output.put_line( emp_info.empno  || '---' ||  emp_info.ename ||'--- '||  emp_info.job);
    
end ;


if:
1.
if 条件  then ... ;
end if;

2.
if 条件  then ...;
else   ....

end if;

3.
if 条件 then ..;
elsif 条件 then ...
else ..
end if ;


set serveroutput on ;
declare
    pnum number := 3 ;
    
begin
    if pnum=1   then   dbms_output.put_line('一');
    elsif pnum=2  then   dbms_output.put_line('二');
    else dbms_output.put_line('其他');
    end if ;   
    
end ;


循环while  do..while  for


do{}while(i<5)  

1.
while 条件
loop 
...
end loop ;

2.
loop 
...
   exit when i>5 ;
end loop;


3
for  i in  1 .. 10
loop

..
end loop ;


示例
set serveroutput on ;

declare
        
begin
  for x in 1 .. 5
    loop
            dbms_output.put_line(x);
    end loop ;
end ;


--1-5之和
declare
        pnum number:=1 ;
        psum number:= 0 ;
begin
        loop
            exit when pnum >5 ;
            psum := psum + pnum ; --sum+= i ;
            pnum := pnum +1 ;
        end loop ;
        dbms_output.put_line(psum);
end ;

游标(光标)cursor  :集合

语法:
    定义
    cursor 光标名(参数列表)
    is
    select ....


光标的属性
    %isopen      %rowcount    %found    %notfound 


--查询并打印全部员工的姓名、薪水
set serveroutput on ;
declare
    --变量、常量、光标(游标)、例外(自定义异常)
  cursor cemp  is select ename ,sal from emp ;
  pename emp.ename%type ; 
  psal emp.sal%type ;
  
begin
      open cemp ;--1.打开光标
      loop    --2.循环 准备获取每一行数据
         fetch  cemp  into pename,psal ;--3.一行一行获取光标的值
         exit when cemp%notfound ;
         
         dbms_output.put_line(pename||'的工资是:'||psal);
         
      end loop ;
      
      
      close cemp ;--关闭光标
    
end ;


--总工资: president 1000   ,manager 800, 其他 400

set serveroutput on ;
declare
    cursor cemp is select empno, job from emp ;
    pempno emp.empno%type ;
    pjob emp.job%type ;
 
begin
   open cemp ;
   loop 
    fetch cemp into pempno,pjob ;
    exit when cemp%notfound ;
    
    --判断职位
    if pjob = 'PRESIDENT'
        then update emp set sal = sal +1000 where empno=pempno ;
    elsif  pjob = 'MANAGER'
        then update emp set sal = sal +800 where empno=pempno ;
    else 
        update emp set sal = sal +400 where empno=pempno ;
    end if ;    
        
        
   end loop ;
    dbms_output.put_line('ok');
   
   close cemp ;
   commit ;  --ACID oracle read commit ,一边(终端)不提交,另一个访问不到
    
end ;


--查询某个部门的员工姓名,带参数的光标


例外(异常)
系统例外
    no_data_found     
    too_many_rows 
    zero_Divide
    value_error:算术或转换错误
    timeout_on_resource:资源等待超时

set serveroutput on ;
declare 
   pnum number ;
   
begin 

   pnum := 1/0 ;
   
   exception 
     when zero_divide then dbms_output.put_line('0不能作为除数');
     when too_many_rows then dbms_output.put_line('行数太多');
     when others then dbms_output.put_line('其他例外..');
end ;


自定义例外

MyException 


try{
    if(xxx) throw new MyException() ;

}catch(){}
catch(){}
catch(){}


set serveroutput on ;
declare 
  myexc  exception ;
  pnum number := 1 ;
   
begin 
    if pnum =1 then raise  myexc ;
    end if;
    exception 
     
end ;


是否存在编号50的部门,如果不存在 ,抛出一个例外;如果存在,将该部门的员工姓名 打印。。

set serveroutput on ;
declare 
  cursor cemp(dno number) is select ename from emp where deptno = dno ;
   pename emp.ename%type ;
   no_emp_found exception ;
   
begin 
   open cemp(50);
     fetch cemp into pename ;
    if cemp%notfound then  raise no_emp_found ;
    
    else 
           loop
                  exit when cemp%notfound ;
                  fetch cemp into pename ;
           end loop ;
    
    
    end if ;
  
        
    exception  
           when no_emp_found then dbms_output.put_line('自定义例外,没有此号部门...');
  
   close cemp;
   
   
end ;


1.统计每年的入职人数
sql: 
    select to_char(HIREDATE,'yyyy' ),count(1) from emp group by to_char(HIREDATE,'yyyy' );
plsql:
    
java:每个人数据全获取, 判断入职年份, 如果1980  , +1  ;+1
set serveroutput on ;
declare 
 cursor cemp is select to_char(HIREDATE,'yyyy' ) from emp ;
  phiredate varchar(4)  ;
  
   count80 number:=0 ;
   count81 number:=0 ;
   count82 number:=0 ;
   count87 number:=0 ;
  
begin 
  open cemp ;
    loop
            fetch cemp into phiredate ;
            exit when cemp%notfound ;
            if phiredate = '1980' then count80 := count80+1 ;
            elsif phiredate = '1981' then count81 := count81+1 ;
            elsif phiredate = '1982' then count82 := count82+1 ;
            else   count87 := count87+1 ;
            end if ;
    end loop ;
  
  close cemp ;
   
   dbms_output.put_line('1980'||count80);
   dbms_output.put_line('1981'||count81);
   dbms_output.put_line('1982'||count82);
   dbms_output.put_line('1987'||count87);
   dbms_output.put_line('总人数'||(count80+count81+count82+count87));
end ;


2.涨工资。 每个10%, 按入职时间顺序涨工资,且涨后的总工资不能超过5万。计算 需要涨工资的人个数 以及涨后的工资总额。

set serveroutput on ;

declare 
 cursor cemp is select empno,sal from emp order by hiredate asc ;
 pempno emp.empno%type ;
 psal emp.sal%type ;
 countEmp number :=0 ;
 salTotal number :=0 ;
  
begin 
    OPEN cemp ;
    loop 
        
        --exit when salTotal > 50000 ;--  5.1
        
        fetch cemp into pempno ,psal ;
        exit when cemp%notfound ;
        
        if salTotal + psal*1.1 < 50000
            --涨工资
           then  update emp set sal = sal*1.1 where empno = pempno;
           countEmp := countEmp +1;
            --salTotal: 50  ,51 
            salTotal := salTotal + psal*1.1 ;  --psal 是变量, sal是表的字段
        else 
            dbms_output.put_line('人数'||countEmp ||'--'|| '涨后的总额'||salTotal);
        
            exit  ;
        
        end if ;
    
    end loop ;
 
    close cemp ;

end ;


3.统计各部门的工资情况。格式如下
部门编号        <2000的人数        2000-4000人数        >4000人数    工资总额
        count1            count2            count3        salTotal
        
光标保存各个部门:10  20  30
set serveroutput on ;

declare 
    cursor cdept is select deptno from dept ;--10  20 30 40
    pdeptno dept.deptno%type ;
    
    --部门中员工的所有工资
    cursor cemp(dno number) is select sal from emp where deptno = dno;
    psal emp.sal%type ;
    
    count1 number;
    count2 number;
    count3 number ;
    
    --各部门工资总额
    salTotal number ;
    
    
begin 
    open  cdept;
    loop  --外层循环:遍历所有的部门 编号;;内层循环:遍历某个部门的所有工资
        fetch cdept into pdeptno ;
        exit when cdept%notfound ;
        count1 :=0 ;
        count2 :=0 ;
        count3 :=0 ;
        select sum(sal) into salTotal from emp where deptno =pdeptno ;
        open  cemp(pdeptno) ;
            loop
                fetch cemp into psal ;
                exit when cemp%notfound ;
                if psal<2000 then count1:=count1+1;
                elsif psal>=2000 and psal<4000 then  count2:=count2+1;
                else count3:= count3+1 ;
                end if ;
                
            end loop ;
        
        
        close cemp ;
        dbms_output.put_line(pdeptno||' '||count1||' '||count2||' '||count3||' '||salTotal);
        
        
    end loop;
    
    close cdept;


end ;

public void hellworld()
{
    System.out.println("hello world")
}

存储过程/存储函数
    方法\函数

存储过程:
create or reaplace procedure 过程名(参数列表)
as
    PLSQL语句 ;
具体语法:

无参

create  procedure 过程名(参数列表)

as
begin 

end ;


示例
set serveroutput on ;

create or replace procedure test1
as 
    pnum number:=10 ;
begin
    dbms_output.put_line('hello:'||pnum);
end ;


调用
--exec test1();
begin
    test1();
    test1();
    test1();
end ;


有参:
    输入参数in
    输出参数out  (返回值)

--传入一个员工编号,给该员工涨500
create or replace procedure raiseSalary(pid in number) 
as 
    psal emp.sal%type ;
begin 
    select sal into psal from emp where empno=pid ;
    update emp set sal = sal + 500 where empno=pid ;
    dbms_output.put_line(psal || '--'||psal+500);
end ;

create or replace procedure raiseSalary(pid in number ,xxx out xxx ) 
.... 


存储函数:与存储过程的最大区别: 必须有return 
    in   out
create [or replace] function 函数名(参数列表)
    return 返回值类型 
as

begin 
    ..
    return  返回值
end ;


--查询某个员工的年收入

null 的运算结果 ->null

create or replace function getTotalSal(pid in number) 
    return number 
as 
    empSal emp.sal%type ;
    empComm emp.comm%type ;
begin 
    select sal ,comm into empSal,empComm from emp where empno = pid ;
    dbms_output.put_line( empSal*12+  nvl( empComm,0));
    return empSal*12+  nvl( empComm,0) ;
end ;

调试
 grant DEBUG CONNECT SESSION  to scott

 grant DEBUG ANY PROCEDURE to scott;

存储过程/存储函数? 
建议:只有一个返回值  存储函数  return 
没有、多个返回值 ,存储过程  out out  out 


返回值:
    
存储函数 :out \ return 

存储过程:out 


存储过程: 传入员工编号,返回姓名、工作

--注意编写的位置:工作台

--存储过程: 传入员工编号,返回姓名、工作
create or replace procedure getEmpInfo(pempno in emp.empno%type, pename out emp.ename%type, pjob out emp.job%type )
as
   
begin 
    select ename  ,job into pename ,pjob from emp where empno = pempno;
end ;


--存储函数
create or replace FUNCTION getEmpFuncInfo2222(pempno in emp.empno%type, pename out emp.ename%type, pjob out emp.job%type )
    return varchar2 
as
   
begin 
    select ename  ,job into pename ,pjob from emp where empno = pempno;
    return null ;
end ;


-查询某个部门的所有员工信息
     select * from emp where deptno = 10 ;
光标来保存集合数据 :out

返回值/输出参数如果是光标类型: 包

包 = 包头+包体

public void aa() 包头
{
    包体

}


包头:右键程序包:
create or replace PACKAGE MYPACKAGE 

AS 
    type empcursor is ref cursor  ;
    procedure queryEmpList(dno in number , empList out empcursor) ;
    
 

END MYPACKAGE;


包体: 右键包- 创建体

CREATE OR REPLACE
PACKAGE BODY MYPACKAGE AS

  procedure queryEmpList(dno in number , empList out empcursor)  AS
  BEGIN
        open empList for 
        select *from emp where deptno = dno;
        
  END queryEmpList;

END MYPACKAGE;
验证:desc mypackage ;

SQLdeveloper无法执行测试package 

触发器:
    与表相关联的,PLSQL程序

    当执行DML,自动执行触发器


语法
    create or replace trigger 触发器名
    before|after
    delete|insert |update [of 列名]
    on 表
    for each row [ when (条件)]
    ...plsql 代码
    /

当插入一个数据时,自动打印“成功”


select *from student;

create trigger logStudent
after 
insert 
on student
declare 
begin 
    dbms_output.put_line('增加成功');
end ;
/


测试
set serveroutput on ;
insert into student(stuno,stuname,stuage) values(22,'zs22',222);

set serveroutput on ;
create trigger logupdateStudent
after 
update of stuname
on student
declare

begin
    dbms_output.put_line('您修改了姓名...');
end ;
/

无论修改多少行,触发器只执行一次。

原因:默认是 语句级触发器,作用于表,只执行一次。


语句级触发器:
    作用于表,只执行一次。
行级触发器:
    作用于每一行,每满足一次条件  都执行一次;可以执行多次触发器
    for each row [when 条件]


行级触发器:
    create or replace trigger logaddStudent
    after
    insert
    on student
    for each row
    declare
    begin
        dbms_output.put_line('增加成功!');
    end;
    
    /


insert into student(stuno,stuname)
select empno,ename from emp;


--不能在非工作时间插入员工信息
周一 - 周五   9:00 - 18:00


星期几:select to_char(sysdate, 'day') from dual;

小时:select to_char(sysdate, 'hh24') from dual;


create or replace trigger securityStudent
before  insert 
on student
begin
        --校验  --不正常
        if    to_char(sysdate,'day')  in ('星期四','星期日')  or     to_number( to_char(sysdate,'hh24') ) not between 9 and 18
        then 
            --禁止插入,例外
            raise_application_error(-20001,'禁止非工作时间插入学生'  );
        end if ;
end ;
/


使用触发器确保:涨工资,涨后的工资 不能少于涨前的工资

create or replace trigger checkSalary
before update 
on emp 
for each row 
begin   --new  old
    if :new.sal < :old.sal  --3000 - 5000 
    then 
    raise_application_error(-20002 , '涨后的工资不能小于涨前的!');
    end if ;
end ;
/


raise_application_error中编号的范围   -20000  -  -20999


数据校验:  web前端  onsubmit   onblur -->   控制器 Servlet/Spring MVC  if() 
        ->数据库 触发器


数据字典(了解) :元数据,  数据库的各种描述信息,系统自带很多表
    dictionary、user_objects 、user_tables、user_tab_columns ;
    
        all_tables

数据字典的命名规范:
    user:当前用户能够使用的
    all:系统中全部的
    dba:管理员
    v$:性能相关

    user_sequences ;
    user_synonyms;
    user_关键字s;
    user_tab_comments 
    all_tab_comments 


DBCA(已管理员身份运行)


数据仓库:分析数据用的,只查询  不DML。

默认密码
sys  change_on_install
system manager
scott tiger


ASM:外设磁盘

快速恢复区 flash_recovery_area :闪回区大小   3G

闪回去越大 ,可以恢复的数据越多,但是  会影响性能

备份:
    热备份 :联机备份 ,归档模式
    冷备份 : 脱机备份


示例方案: scott   sh   hr 
制定脚本:  在数据库创建完毕时,自动执行的脚本

insert into ....   ->  aa.sql


连接模式
    专用服务器  
    共享服务器 


监听出错:
    监听程序  -》忽略错误,原因:在创建第一个数据库时  已经有了监听器。因此不用在创建新的监听器

假设:报错监听失败。


维护监听器:  Net  Manager


https://localhost:1158/em


sqlplus scott/tiger

sqlplus scott/tiger@sid

更改默认regedit中修改

计算机\HKEY_LOCAL_MACHINE\SOFTWARE\ORACLE\KEY_OraDb11g_home1 :ORACLE_SID  


闪回
    作用:  将错误的DML 并且commit, 进行撤销  (撤销已提交的事务);
        还原删除的表 drop table xxx ;
        获取表上的历史记录
        
    类型:
        闪回表中的数据:将表中的数据  回退到历史的某一个点
        闪回删除的表:还原表
        闪回事务查询: undo_sql
        闪回数据库(了解):将数据库 中的数据  回退到历史的某一个点
          闪回归档日志(了解)


1.闪回表中的数据:将表中的数据  回退到历史的某一个点
        
必须sys
show parameter undo;
        
假设闪存区3G
undo_retention:900 ,超过闪存区的数据 必须在900秒内闪回

alter system set undo_retention=1200 scope = both ;
both| memory 当前数据库有效,重启无效| spfile  当前数据库无效,重启有效


    闪回:时间点SCN

    闪回:必须知道 回退的时间点 或者SCN  ,时间->SCN

时间->SCN :
    select  timestamp_to_scn(sysdate) scn from dual ; 
    
flashback
create table testfb 
(
id number ,
name varchar(10)
);

insert into testfb values(1,'a');
insert into testfb values(2,'b');
insert into testfb values(1,'c');
commit ;

此时SCN:3607794

删除id=1
commit ;

闪回:
flashback table testfb  to scn 3607794 ;

如果某个用户在闪回时权限不足,需要授权:
sys:
    grant flashback any table to scott;

闪回 可以跨越commit 回退。

想:
3天
1commit  commit   commit
            "2019-8-8  20:00" -> date ..  ->scn

2commit
3commit

要闪回:必须知道 时间点

2.闪回删除的表(还原oracle回收站中的表 )
        
    查看回收站
        show recyclebin;
    默认情况下:如果回收站中重名,闪回的是最近一次删除的表
    如果闪回的表 和库中目前的表 重名 ,则冲突,必须 重命名rename to..

    flashback table  表名  to before drop ;
    flashback table  "回收站中的名字"  to before drop ;

    清空回收站 purge recyclebin;


    彻底删除某一张表(不过回收站): drop table testfb2  purge ;

    普通用户: 删除->回收站 ->  清空|还原

    管理员:删除表 不过回收站,直接彻底删除。

    是否闪回表中的触发器:
        A(触发器) -> 删除->回收站  ->闪回表时 是否连同触发器一起闪回

flashback table 表明 to before drop  [rename to 新表名] enable|disable(默认) triggers ;

create table testfb4
(
id number ,
name varchar(10)
);

flashback table enable triggers  testfb4   to before drop  ;


3闪回事务查询
    区别:
        闪回dml+commit:的不同之处:  

                闪回dml+commit : 依赖时间  ->scn
                闪回事务:依赖的是 提交次数(undo_sql)
a.提交次数 ? 闪回版本查询(事务编号)

坑: ( bug)dml操作数据时  不要太快(批量复制 )
凡是能够撤销的 事务,都必须提前开日日志:在sys中执行alter database add supplemental log data;


create table tb_version(id number,name varchar2(10)) ;

insert into tb_version values(11,'a1');
insert into tb_version values(12,'a1');
insert into tb_version values(13,'a1');
commit;

insert into tb_version values(21,'b1');
insert into tb_version values(22,'a1');
insert into tb_version values(23,'a1');
commit;

insert into tb_version values(31,'c1');
insert into tb_version values(32,'a1');
insert into tb_version values(33,'a1');
commit;

--bug  :如果插入数据且commit 速度太快,可能会丢失 事务信息

闪回版本查询: 
    版本信息:伪列
select  id,name ,versions_xid,versions_operation,versions_starttime,versions_endtime from tb_version versions between timestamp  minvalue   and maxvalue;

"2019-05-19" ->timestamp 类型
"2019-05-21"


select  id,name,versions_xid,versions_operation,versions_starttime,versions_endtime from tb_version versions between timestamp  minvalue   and maxvalue ;

事务闪回的核心:  查询undo_sql  ,执行即可
需要授权: grant select any transaction to scott;

undo_sql存在于表: desc flashback_transaction_query;
查询undo_sql前 需要在sys中修改设置:alter database add supplemental log data;


select OPERATION ,UNDO_SQL from  flashback_transaction_query   where  XID  ='050013005F080000';

select  XID,OPERATION ,UNDO_SQL from  flashback_transaction_query ;


导入导出
    命令行cmd
导出:exp  
        exp不是sql语句,是一个工具,直接在cmd中执行
    a.表方式 
    exp scott/[email protected]/ORCL file=d:/back/bk.dmp log=d:/back/log.log tables=emp,dept

    b.用户方式:
    exp scott/[email protected]/ORCL file=d:/back/bk2.dmp log=d:/back/log2.log 
    
    c.全库方式:DBA角色的   (sys  / system )
    exp system/[email protected]/ORCL file=d:/back/bk2.dmp log=d:/back/log2.log full=y

导入
    a.表方式 
    imp hr/[email protected]/ORCL  file=d:/back/bk.dmp log=d:/back/log.log tables=emp,dept  fromuser=scott touser=hr commit=y ignore=y 

    b.用户方式:(DBA角色)
    imp system/[email protected]/ORCL  file=d:/back/bk2.dmp log=d:/back/log2.log   fromuser=scott touser=hr commit=y ignore=y 


    c.全库方式:
imp system/[email protected]/ORCL  file=d:/back/bk2.dmp log=d:/back/log2.log    commit=y ignore=y destroy=y

向导模式
exp
imp

分布式数据库:
    大->小 
    物理上分开存放,逻辑上一个整体
    独立性:客户端不必关心数据如何分割和存储 ,只需要关心数据本身即可

    分布式数据库三种操作:
    a.本地操作
    b.远程操作 sqlplus scott/[email protected]/orcl
        注意:  i. 关闭远程防火墙
            ii.远程: 将2个文件(tnsnames.ora、listener.ora) 的Host值 改成   IP地址或计算机名

    c.分布操作
        借助于数据库链路:


    
        
    其中l2vm 是链路名
    remoteORCL是服务名 ,用于连接远程的服务(orcl)
        创建服务名: net manager

    创建链路:(链路的单向的)
create database link l2vm  connect to  scott identified by tiger  using 'remoteORCL';

    


同时操作本地和远端 ,关联查询
select ename,dname from emp@l2vm e,dept d where  e.deptno = d.deptno ;

emp@l2vm-> remoteemp


select ename,dname from emp@l2vm e,dept d where  e.deptno = d.deptno ;


创建同义词 屏蔽掉分布式访问的 关键字
create synonym remoteemp for emp@l2vm ;


select ename,dname from remoteemp  e,dept d where  e.deptno = d.deptno ;

视图
create view empremoteview
as 
  select ename,dname from remoteemp  e,dept d where  e.deptno = d.deptno ;


select * from empremoteview;

查看星期的显示格式: select to_char(sysdate,'day') from dual;

快照:可以备份远程数据库(快照有一定延迟)
create snapshot empdeptss
refresh start with sysdate 
next next_day(sysdate,'星期三')   
as
select * from emp@l2vm 

;


触发器:(实时备份) 
工资问题:如果本地数据库中修改工资了,则同步到远程

create or replace trigger update_emp
after update on emp 
for each row

begin
    update emp@l2vm  set sal=:new.sal  where empno=:new.empno ;

end ;
/

update后注意commit;


EM管理器(了解)
       OracleDBConsocleorcl
     关闭远程防火墙  本地->VM

https://192.168.2.128:1158/em

    
    临时表:
        中间产物,用完就自动删除
    select *from emp  order by sal ;

    延迟:约束

name :   check( length(name) >2 )  ->延迟

a
b


commit ;  延迟报错


用户权限:
    登录验证
    密码校验sqlplus scott/tiger  


外部校验 条件: 当前系统用户必须是 dba角色  (查看:右键计算机- 本地用户和组 )
    外部校验 sqlplus / as sysdba   (自动屏蔽密码校验)

    全局校验: 生物认证  、 token(令牌环,银行卡:  U盾)


预定义账户:
    scott
    sys : 最高权限(一切权限)
    system     :DBA权限


权限:
    系统权限: 允许用户执行对【数据库】的特定行为  (创建用户、创建表)
    对象权限: 允许用户执行一个特定的【对象】  ( scott查看hr的一张表)

    系统权限:
    创建用户
    create user  yq identified by yq ;  没有任何权限(包含登录权限)

        赋予yq登录权限grant  CREATE SESSION to yq;


    对象权限:让yq可以查询scott用户的emp表
        grant select on scott.emp to yq ;
    
yq查看:
    select *from scott.emp;
 

你可能感兴趣的:(数据库)