Oracle (05)外键约束.序列.索引.视图.分页查询技术.排序分页查询.数据库表格设计范式

版权声明:cxyo.cn https://blog.csdn.net/weixin_44075537/article/details/85033470

外键约束 (完整性约束)(fk) *****

牵扯到两个表格:

概念:

1.  外键约束, 是存在两个表格的操作 !
2.  一张表格我们称为主表(父表) , 另一张叫做从表(子表) , 定义了外键约束的表格属于从表 !
3.  从表的外键字段, 是在参考主表中的主键 或 unique约束的字段 ! (被参考的字段 必须具备唯一性)
4.  从表外键字段的取值范围, 受限与主表的参考字段, 外键的取值, 必须是参考字段的值或者null! 

作用:

外键约束 保证了参数的完整性, 限定了一个列的取值范围 !

外键的实现

编写外键时 , 出现外键的字段称为从表, 主表必须创建在从表之前!

编写外键时, 主表是被参考的表, 不用做任何的额外操作 !

格式:

create table 从表名(
字段名 字段类型(长度) references 主表名(参考字段)
);

案例:

建立主外键关系, 使用用户和订单表

1.  创建用户主表

drop table user15;
create table user15(
    id number constraint user15_id_pk primary key,
    uname varchar2(30)
);

2.  创建订单从表
drop table order15;
create table order15(
    id number constraint order15_id_pk primary key,
    info varchar2(100),
    userid number references user15(id)
);

测试向订单表格(从表)插入数据

insert into order15 values(10000001.‘hahahaha’,10001);
发生了错误:
SQL 错误: ORA-02291: 违反完整约束条件

发生上述错误的原因在于 从表中的外键的取值, 在主表的被参考字段中不存在!


尝试向主表插入数据

insert into user15 values(10001,‘admin’);

测试向订单表格(从表)插入数据

insert into order15 values(10000001.‘hahahaha’,10001);

删除数据

在删除主表数据时, 需要先将从表中参考的数据 删除/置空 !

否则会出现错误: ORA-02292: 违反完整约束条件 已找到子记录

  1. 尝试删除id为10001的用户
    delete from user15 where id=10001;
    commit;

上述的操作, 发生了错误
ORA-02292: 违反完整约束条件 已找到子记录

  1. 先删除从表中的数据, 再尝试删除id为10001的用户

    delete from order15 where userid=10001;
    delete from user15 where id=10001;
    commit;

  2. 或者尝试使用置空操作, 来删除主表数据

    update order15 set userid=null where userid=10001;
    delete from user15 where id=10001;
    commit;

删除被外键所关联的表格

在删除主表时, 必须先删除从表, 或取消表格间的关联关系 !

否则会报错: SQL 错误: ORA-02449: 表中的唯一/主键被外键引用

删除主表操作:

  1. 尝试删除user15表格

    drop table user15;

  2. 尝试删除从表后 . 再删除主表 !

    drop table order15;
    drop table user15;

    上述的操作, 确实没有报错, 删除了从表以后. 就可以直接删除主表了 !

    但是其实上述的操作 , 是不建议的 . 因为表格之间关系太复杂 !

删除一个表格时, 直接取消外键关联关系 ! ***

格式: drop table 主表名 cascade constraints;

主表是被参考的表格, 主表在删除时, 会抛出’表中的唯一/主键被外键引用’的错误

在删除时, 可以直接在删除表格语句后, 添加取消关系的关键字

cascade constraints;

这样删除的主表 , 会取消从表的外键关系, 并不会删除从表 !

案例:

1.  创建用户主表

drop table user15;
create table user15(
    id number constraint user15_id_pk primary key,
    uname varchar2(30)
);

2.  创建订单从表
drop table order15;
create table order15(
    id number constraint order15_id_pk primary key,
    info varchar2(100),
    userid number references user15(id)
);

尝试使用cascade constraints 删除并取消关联关系

drop table user15 cascade constraints;

级联操作(主表数据的删除) ***

两种不同的操作:

  • 级联置空
    删除主表中被参考数据时, 从表外键字段数据自动设置为null
    关键字: on delete set null

  • 级联删除
    删除主表中被参考数据时, 从表外键字段数据自动删除一行 !
    关键字: on delete cascade;

语法格式:

在声明外键的语句后, 加入级联关键字即可 ; 

例如: userid number constraint order15_userid_fk references user15(id) on delete set null

级联置空案例:

1.  创建用户主表

drop table user15 cascade constraints;
create table user15(
    id number constraint user15_id_pk primary key,
    uname varchar2(30)
);

2.  创建订单从表
drop table order15 cascade constraints;
create table order15(
    id number constraint order15_id_pk primary key,
    info varchar2(100),
    userid number constraint order15_userid_fk references user15(id) on delete set null
);  

尝试向上述的表格中插入数据

insert into user15 values(10001,'admin');
insert into user15 values(10002,'root');    
insert into user15 values(10003,'dongfei');  

insert into order15 values(10000001,'hahaha1',10001);
insert into order15 values(10000002,'hahaha2',10002);
insert into order15 values(10000003,'hahaha3',10002);
insert into order15 values(10000004,'hahaha4',10001);
commit;

在数据已经存在的情况下, 尝试删除主表数据 !

delete from user15 where id=10002;
commit;

级联删除案例: 

1.  创建用户主表

drop table user15 cascade constraints;
create table user15(
    id number constraint user15_id_pk primary key,
    uname varchar2(30)
);

2.  创建订单从表
drop table order15 cascade constraints;
create table order15(
    id number constraint order15_id_pk primary key,
    info varchar2(100),
    userid number constraint order15_userid_fk references user15(id) on delete cascade
);  

尝试向上述的表格中插入数据

insert into user15 values(10001,'admin');
insert into user15 values(10002,'root');    
insert into user15 values(10003,'dongfei');  

insert into order15 values(10000001,'hahaha1',10001);
insert into order15 values(10000002,'hahaha2',10002);
insert into order15 values(10000003,'hahaha3',10002);
insert into order15 values(10000004,'hahaha4',10001);
commit;

在数据已经存在的情况下, 尝试删除主表数据 !

delete from user15 where id=10002;
commit;

外键的表级约束 *

格式:

create table 表名(
字段列表…,
constraint 别名 foreign key(本表中的外键字段) references 主表名(主表字段) 级联关键字(on delete set null|on delete cascade)
);

案例:

    1.  创建用户主表

drop table user15 cascade constraints;
create table user15(
    id number constraint user15_id_pk primary key,
    uname varchar2(30)
);

2.  创建订单从表
drop table order15 cascade constraints;
create table order15(
    id number constraint order15_id_pk primary key,
    info varchar2(100),
    userid number,
    constraint order15_userid_fk foreign key(userid) references user15(id) on delete cascade
);  

尝试向上述的表格中插入数据

insert into user15 values(10001,'admin');
insert into user15 values(10002,'root');    
insert into user15 values(10003,'dongfei');  

insert into order15 values(10000001,'hahaha1',10001);
insert into order15 values(10000002,'hahaha2',10002);
insert into order15 values(10000003,'hahaha3',10002);
insert into order15 values(10000004,'hahaha4',10001);
commit;

在数据已经存在的情况下, 尝试删除主表数据 !

delete from user15 where id=10002;
commit;

先建立表格 后添加约束 (所有约束) ***

修改表结构, 来实现后添加约束的操作 !

一个表格 存在约束 和 不存在约束, 在大量的数据插入时, 不存在约束的表格, 效率更高 !

如果在进行数据初始化时 (给表格添加初始的行) , 我们一般在创建表格后. 不添加约束, 等数据初始化完毕后. 再通过修改表结构, 给它添加约束 !

后添加约束 需要注意:

表格中原本存在的数据, 一定要是符合约束条件的 , 否则会出错!

格式:

alter table 表名 add constraint 约束别名 约束关键字(字段名);

案例:

  1. 创建表格 person15

    drop table person15 cascade constraints;

    create table person15(
    id number,
    name varchar2(30),
    age number
    );

  2. 插入数据
    insert into person15 values(10001,‘dongfei’,80);
    insert into person15 values(10002,‘zhulei’,18);
    insert into person15 values(10003,‘yezhibin’,12);
    commit;

  3. 通过修改表结构, 添加约束

    alter table person15 add constraint person15_id_pk primary key(id);

删除一个约束 ***

与添加约束一样, 都是通过修改表结构操作 来完成的 !

格式:

alter table 表名 drop constraint 约束别名;

案例:

alter table person15 drop constraint person15_id_pk;

数据库的其他对象

下面要学习的其它对象, 对于它们在数据库中的创建与删除操作 , 与表格操作 基本一致 !

序列 *****

什么是序列?

有时我们在数据的插入时, 需要一些可以自增长的变量 ~

例如: 我们在创建一行数据时, 需要添加唯一标识的id,
我们一般会将id设置为主键, 主键时不可重复的 .

我们怎么做,  才可以保证id 不会重复? 且有效? 

序列就是解决这个问题的 , 类似Java中的一个整型的变量(int xx = 0;);
可以在语句中 直接使用, 并让其自增长(自身加一 类似Java中的i++)!

我们使用序列, 一般是在insert 语句 和 select语句中!

在Java程序中 , 进行数据的插入. 一般是先通过select语句, 查询到当前的序列值, 然后再使用值, 插入到行中 !

语法格式:

  • 创建序列的语法格式:
    create sequence 序列名称;
    序列的命名规范:表名_字段名_seq;
    (相当于在Java中创建了一个变量i: int i=0;)

  • 使用序列的语法格式:
    序列名称.nextval
    (相当于在Java中使用变量i:i++)
    可以得到一个整型的值, 且自身会加一 !
    这个自增长的值 是从1 开始的!

  • 删除序列的语法格式:
    drop sequence 序列名称;

案例:

  1. 创建一个表格
    drop table user15 cascade constraints;
    create table user15(
    id number constraint user15_id_pk primary key,
    uname varchar2(32),
    upass varchar2(32)
    );

  2. 创建一个序列
    drop sequence user15_id_seq;
    create sequence user15_id_seq;

  3. 插入一些数据

    insert into user15 values(user15_id_seq.nextval,‘dongfei’,‘aijiaoji’);
    insert into user15 values(user15_id_seq.nextval,‘gaofan’,‘aixuexijiaoji’);
    insert into user15 values(user15_id_seq.nextval,‘zhulei’,‘aijiaohahaha’);
    commit;

索引 (了解)

数据库是一款软件, 用来存储数据的仓库 !
索引是通过消耗大量的时间和空间 来达到加速查询的目的 !
索引技术 是数据库自动使用的 , 一个表格中只存在一个索引就够了!
如果一个表格存在主键, 那么在主键创建时, 索引就已经存在了 !(由系统创建的);

命名规范: 表名_字段名_index

语法:

创建:
    create index 索引名称 on 表名(字段名);

删除:
    drop index 索引名称;

案例:

自己编写索引, 在数据量小的时候, 查询的速度 ,肉眼是无法观察到的 !

create index user15_uname_index on user15(uname);

drop index user15_uname_index;

视图 *****

查询一个不存在的表格

select * from hahahahha;

上面的操作, 出现了错误, 表或视图不存在

视图的概念:

视图就是一条SELECT语句 !

我们可以将一条SELECT语句的结果, 生成为视图, 然后把这个视图当作表格来操作!

相对于select语句产生的数据结果而言, 视图本身的空间很小!

作用:

可以对同一份数据 做出不同的表现 !  可以用来简化子查询 !

还可以用来控制查询权限 !

注意:

在操作视图时, 对视图的修改, 会影响表格!      

创建/替换 视图的语法格式:

create or replace view 视图名称 as 查询语句;

删除视图的语法格式:

drop view 视图名称;

对于视图的操作, 与 表格一致!

案例:

根据多表查询, 生成一个视图:

根据员工+部门表, 生成视图: (包含了员工的id,员工的姓,员工的月薪,部门的名称)

  1. 先编写出查询语句:

    select e.id,e.last_name,e.salary,d.name from s_emp e,s_dept d where e.dept_id=d.id;

  2. 根据上面的语句, 创建视图

    create or replace view s_e_d as select e.id,e.last_name,e.salary,d.name from s_emp e,s_dept d where e.dept_id=d.id;

  3. 把视图当前表来查询
    select id,name from s_e_d;

分页查询技术

在数据库中执行查询操作时, 通过添加where条件, 限制查询的内容, 进而实现分页操作!

分页查询的常见公式:  

    分页查询时 id(行号) 的范围:

        -   开始范围:   大于(当前页数-1)*一页准备显示的数量
        -   结束范围:   小于等于 当前页数*一页准备显示的数量

查询员工表格(id) , 分页显示,一页显示10个:

查询第一页: 

    select id   from s_emp where id>0 and id<=10;

查询第二页:

    select id   from s_emp where id>10 and id<=20;

查询第三页:

    select id   from s_emp where id>20 and id<=30;

通过行号来进行分页查询 ***

上述的案例 , 在一些特殊情况(id不连续)下 出现了错误

伪列: 在表格中不存在, 但是可以使用的列 !

行号(rownum) 结果集中当前行的 行号

  • 尝试查询行号:

    select rownum from s_emp;

  • 查询第一页

    select id from s_emp where rownum>0 and rownum<=10;

  • 查询第二页

    select id from s_emp where rownum>10 and rownum<=20;

行号在查询 比较时, 存在一个特点: 逐行判断, 当某一行数据不匹配时, 流程结束 !

那么这时就无法通过rownum来进行分页查询 ,因为查询第一页以后的数据, 都查询不到 !

可以借助子查询 / 视图 将rownum这个伪列, 变成一个存在的列 ! 来完成分页 !

查询第二页: *****

1.  子语句: 

    select rownum r,id from s_emp;

2.  编写select语句 查询上面的子语句
    select r,id from (select rownum r,id from s_emp) where r>10 and r<=20;

排序分页查询 *****

三层嵌套子查询:

-   最内层查询   : 查询所有行的数据, 并进行排序

-   中间层查询   : 查询排序后的数据, 给行号起别名, 将行号变为 '存在的' 列! 并进行部分数据的过滤

-   最外层查询   : 使用中间层的 行号别名 进行数据的过滤 ,实现分页!

查询s_emp表格(id,salary) , 一页显示10个 ,根据salary升序排序 (第二页):

最内层: select  id,salary from s_emp order by salary;

中间层: select id,salary,rownum r from (最内层) where rownum<=20;

最外层: select id,salary from(中间层) where r>10;

语句:

select id,salary from(select id,salary,rownum r from (select  id,salary from s_emp order by salary) where rownum<=20) where r>10;

数据库表格设计范式

第一范式: 数据库表格中的列 不可再分 , 一行中单列的值只有一个!

第二范式: 要求,数据库中的表格在设计时, 表中的每一行数据 都可以被唯一区分 !(表格必须存在主键)

第三范式: 消除依赖传递: 满足第三范式, 必须先满足第二范式!

    主外键关联时,  应只关联主表中的主键字段! 

猜你喜欢

转载自blog.csdn.net/weixin_44075537/article/details/85033470