8.3行转列
/* id name course score 1 张三 语文 81 2 张三 数学 75 3 李四 语文 81 4 李四 数学 90 5 王五 语文 81 6 王五 数学 100 7 王五 英语 90 create table tb_student( id number(4) , name varchar2(20), course varchar2(20), score number(5,2) ); insert into tb_student values(1,'张三','语文',81); insert into tb_student values(2,'张三','数学',75); insert into tb_student values(3,'李四','语文',81); insert into tb_student values(4,'李四','数学',90); insert into tb_student values(5,'王五','语文',81); insert into tb_student values(6,'王五','数学',100); insert into tb_student values(7,'王五','英语',90); commit; drop table tb_student cascade constraints; */ select * from tb_student; --使用一条sql语句,查询每门课都大于80分的学生姓名 --数据 : 学生姓名 name --来源 : tb_student --条件 : 1)学生考的课程数目 = 总课程数目 2)每一学生的所有课程中最低分数>80 --一共存在几门课程 select count(distinct course) from tb_student; --按照人名分组,计算总课程数,以及每个人所有课程的最低分数 select name from tb_student group by name having count(1) = (总课程数目) and min(score) > 80 ; select name from tb_student group by name having count(1) = (select count(distinct course) from tb_student) and min(score) > 80; --行专列 select name 姓名,decode(course,'语文',score) 语文,decode(course,'数学',score) 数学,decode(course,'英语',score) 英语 from tb_student; select name 姓名, max(decode(course, '语文', score)) 语文, max(decode(course, '数学', score)) 数学, min(decode(course, '英语', score)) 英语 from tb_student group by name;
8.3.1链表查询(表连接)
8.3.2表连接(92)
1,当我们获取的数据不是来自于同一张表而是来自于多张表时就需要使用到表连接
2,select * from emp;
select * from dept;
注意:同名列 非* 必须区分
数据源 、关系列、 过滤条件、字段
8.3.3笛卡尔积
1,非* 必须区分 使用表名 或别名.区分
select * from emp , dept; select ename , dname from emp , dept; select ename, dname, e.deptno from emp e, dept d;
8.3.4等值连接(在笛卡尔积基础上 取条件列相同的值)
--员工名称及部门名称select ename, dname, e.deptno from emp e, dept d where e.deptno = d.deptno; --找出30部门的员工名称及部门名称:先关联后过滤select ename, dname, e.deptno from emp e, dept d where e.deptno = d.deptno and e.deptno = 30; --记录很多时 :先过滤后关联 -- 数据来源: emp (select * from emp where deptno=30) e , dept(select * from dept where deptno=30) dselect * from emp where deptno = 30;select * from dept where deptno = 30; -- 查询的字段:ename, dname, e.deptno -- 条件:e.deptno=d.deptno , deptno=30 select ename, dname, e.deptno from (select * from emp where deptno = 30) e, (select * from dept where deptno = 30) d where e.deptno = d.deptno;
8.3.5 非等值连接 > < != <>between and
--查询员工姓名,工资及等级 --900 属于哪个等级select grade from salgrade where 900 > losal and 900 < hisal;select grade from salgrade where 900 between losal and hisal; --查询员工姓名,工资及等级 -- 数据源: emp e, salgrade s -- 字段: ename, grade, sal -- sal between losal and hisalselect ename, grade, sal from salgrade s, emp e where sal between losal and hisal;
8.3.6 自连接: 特殊的等值连接 (来自于同一张表)
--找出 存在上级的员工姓名 及上级名称 -- 数据来源: emp e, emp m -- 字段: e.ename, m.ename -- 条件: e.mgr=m.empnoselect e.ename, m.ename from emp e, emp m where e.mgr = m.empno;
8.3.7外连接
1,看逗号, 主表在,的左边就叫左外连接主表在,的右边叫右连接
--找出 所有的员工姓名 及上级名称 --找出 所有部门的员工数 及部门名称 select dname, nu from dept d, (select count(1) nu, deptno from emp group by deptno) e where d.deptno(+) = e.deptno;
8.3.8表连接(99)
1,交叉连接 cross join --->笛卡尔积
select * from emp cross join dept;
2,自然连接(主外键、同名列) natural join -->等值连接
select * from emp natural join dept; --在指定列过程中同名列归共同所有(*除外) select deptno,e.ename,d.dname from emp e natural join dept d;
3,join using连接(同名列) -->等值连接
select deptno,e.ename,d.dname from emp e join dept d using(deptno);
4,[inner]join on 连接 -->等值连接 非等值 自连接 (解决一切) 关系列必须区分
-- natrual 等值 select ename, dname from emp natural join dept where deptno = 30; --using select ename, dname from emp join dept using (deptno) where deptno = 30; --on select ename, dname from emp join dept on emp.deptno = dept.deptno where emp.deptno = 30; --on 非等值连接 、自连接 --部门编号为30的员工名称 工资等级 select ename, grade from emp e join salgrade s on e.sal between s.losal and s.hisal where deptno = 30; --部门编号为30的员工名称 上级名称 select e.ename, m.ename mname from emp e join emp m on e.mgr = m.empno where e.deptno = 30; --部门编号为30的员工 员工名称 部门名称 工资等级 上级名称 select e.ename, dname, grade, m.ename mname from emp e join dept d on e.deptno = d.deptno join salgrade s on e.sal between s.losal and s.hisal join emp m on e.mgr = m.empno where e.deptno = 30;
5,left|right [outer] join on|using -->外连接
--所有部门的 部门名称,员工数 --左外 select dname, n from dept d 10.2.6. 全连接 11. DML DML(Data Manipulation Language 数据操控语言)用于操作数据库对象中包含的数据,也就是说操 作的单位是记录。 DML 的主要语句(操作) left outer join (select deptno, count(1) n from emp group by deptno) i on d.deptno = i.deptno; select dname, n from dept d left outer join (select deptno, count(1) n from emp group by deptno) i using (deptno); --右外 select dname, n from (select deptno, count(1) n from emp group by deptno) i right outer join dept d on d.deptno = i.deptno;
6,full join on|using -->全连接 满足直接匹配,不满足 相互补充null ,确保 所有表的记录 都至少出 现一次
select * from (select 1 no, 'a' "name" from dual union select 2 no, 'b' "name" from dual) a full join (select 1 no, 'c' "name" from dual union select 3 no, 'd' "name" from dual) b on a.no = b.no; select * from (select 1 no, 'a' "name" from dual union select 2 no, 'b' "name" from dual) a full join (select 1 no, 'c' "name" from dual union select 3 no, 'd' "name" from dual) b using (no);
8.3.9rowid和rownum
1,rowid rownum 相当于伪列存在,是数据库的对象之一 rowid 行的唯一标识,相当于行的地址,插入行记录时候确定的不变的
2,去重:当表中存在主键字段|唯一字段的时候-->可以根据主键|唯一字段实现去重 当表中不存在主键字段|唯一字段的时候--> 可以根据rowid
insert into tb_student values(1,'张三','语文',81); insert into tb_student values(2,'张三','数学',75); insert into tb_student values(3,'李四','语文',81); insert into tb_student values(4,'李四','数学',90); insert into tb_student values(5,'王五','语文',81); insert into tb_student values(6,'王五','数学',100); insert into tb_student values(7,'王五','英语',90); commit; --查询到要保留的数据 select min(rowid) from tb_student group by id,name,course,score; --查询到要删除的数据 select * from tb_student where not rowid in (select min(rowid) from tb_student group by id,name,course,score); --删除这些重复数据 delete from tb_student where not rowid in (select min(rowid) from tb_student group by id,name,course,score);
3,rownum 结果集的序号:只要存在一个结果集select,就存在属于这个结果集的rownum 从1开始,一次+1
select empno,ename,sal,rowid,rownum from emp; --如果存在rownum 与 排序 : 需要嵌套select,内部select做排序,外部select做确定rownum select empno,ename,sal,rownum from emp; select deptno,dname,rownum from dept order by deptno desc; --对已经确定的结果的rownum进行判断使用 select * from (select empno,ename,sal,rownum rn from emp) where rn >= 5; --分页 每页显示3条数据n=3 1,2,3 4,5,6 7,8,9 --查询员工的信息要求根据员工薪资做降序排序,找到第二页数据 i = 2 --每页的第一条数据: 1 n 每页的最后一条 : n*i select empno,ename,sal,rownum from emp order by sal desc; --如果有排序存在,对于已经排序之后的结果集再次确定rownum select empno,ename,sal,rn,rownum num from (select empno,ename,sal,rownum rn from emp order by sal desc); select * from (select empno, ename, sal, rownum num from (select empno, ename, sal from emp order by sal desc)) where num > 4 and num <= 6; --真分页 --假分页
8.4表设计
1,表设计 --三范式: 1)列不可再分|字段的原子性 2)为表中的字段添加主键,区分数据的唯一 3)表中的属性应该依赖于主键字段,不应该依赖于非主键字段 --> 拆分表.主外键关联约束
--约束 : --主键约束 : 唯一+飞空 --唯一约束 --非空约束 --默认约束 --检查约束 --外键约束 : --A 主表|父表: 主键字段 Dept->deptno --B 从表|子表: 外键字段 参考 主表中的主键字段 Emp--> deptno 参考 Dept-> deptno --设计表 : --1.表 : 表名 --2.字段 : 字段名 字段类型 约束 --3.表与表之间的关系 -- 一对一 : 用户表 身份证信息表 --> 主外键关联关系 -- 一对多|多对一 : 员工与部门 学生与班级 -->主外键关联关系 -- 多对多 : 中间表
8.4.1DDL:会套模板
--表创建 create --表修该 alter --表删除 drop
1. 创建表,不添加约束 create table 表名( 字段名 字段类型, 字段名 字段类型, .... )
--学生表 create table student( sid number(5), sname varchar2(15), --(15)默认字节数 sage number(2), sgender char(1 char), --(1 char) 1个字符 hiredate date, phone varchar2(11), cid number(3) ); --1)创建表 + 字段后添加约束 ,不指定约束名 ,简单 create table student( --主键约束 primary key sid number(5) primary key , --非空约束 ) not null sname varchar2(15) not null, --(15)默认字节数 --检查约束 check() sage number(2) check(sage>=18 and sage<=40), --检查约束 sgender char(1 char) check(sgender in ('男','女')), --(1 char) 1个字符 --默认约束 default(默认值) hiredate date default(sysdate), --唯一约束 phone varchar2(11) unique, --外键约束,外键必须是其他表的主键 cid number(3) references clazz(cid) ); create table clazz( --主键约束 cid number(3) p rimary key, --非空约束 cname varchar(15) not null ) --2)创建表 + 字段后添加约束 ,指定约束名 create table student( --主键约束 primary key --约束条件constraints sid number(5) constraints pk_student primary key , --非空约束 ) not null sname varchar2(15) constraints sname_not_null not null, --(15)默认字节数 --检查约束 check() sage number(2) check(sage>=18 and sage<=40), --检查约束 sgender char(1 char) check(sgender in ('男','女')), --(1 char) 1个字符 --默认约束 default(默认值) hiredate date default(sysdate), --唯一约束 phone varchar2(11) unique, --外键约束 cid number(3) references clazz(cid) ); --3)创建表 + 表结构结束之前添加约束 ,指定约束名 create table student( sid number(5), sname varchar2(15), sage number(2), sgender char(1 char), hiredate date, phone varchar2(11), cid number(3), --为指定的字段添加约束 constraints pk_student_sid primary key(sid), constraints sname_not_null check(sname is not null), constraints student_check_sgender check(sgender in ('男','女')), constraints fk_cid foreign key(cid) references clazz(cid) ); --4)创建表结构结束之后追加约束 alter table student add constraints pk_student_sid primary key(sid); alter table student add constraints sname_not_null check(sname is not null); alter table student modify hiredate default sysdate; --modify使用在alter结构中添加默认约束 alter table student add constraints fk_cid foreign key(cid) references clazz(cid); --插入数据 insert into clazz values(204,'java52'); insert into clazz values(205,'db22'); insert into student values(1001,'zhangsan',18,'男',sysdate,'1301000000',204); insert into student values(1002,null,30,'女',sysdate,'1301000009',204); insert into student(sid,sname) values(1003,'王五'); --删除表 drop table student; select * from clazz; select * from student; --加入注释 comment on table student is '学生表'; comment on column student.sid is '学生编号,主键'; comment on column student.sname is '学生名字'; comment on column student.cid is '所在班级编号,外键';
8.4.2三范式
-
表设计 : 1.三范式 最终的目的避免数据重复冗余, 1NF-->列不可再分最小原子 (避免重复); 2NF-->主键依赖(确定唯一); 3NF-->消除传递依赖(建立主外键关联 拆分表); 2.主外键约束 : 主表|父表 : 被从表依赖|参考引用的表 Dept 从表|子表 : 存在外键字段的表 Emp 3.表与表之间的关系: 1.一对一 ; 用户表 身份证表 --> 主外键关联关系
2. 多对一|一对多 : 学生表 班级表|员工表 与 部门表 --> 主外键关联关系 3.多对多 : 通过中间表描述 4.表结构 表名 字段 字段的类型 字段的约束 DDL 数据定义语言 1.create 2.alter 3.drop
--创建表,不添加约束 create table tb_user( userid number(5), username varchar2(6 char), --(6 char)6个字符 ,默认字节数 userpwd varchar2(20), age number(3) , gender char(3) , email varchar2(30), regtime date );
8.4.3约束的分类
-
约束的分类: 主键约束 primary key 唯一约束 unique 非空约束 not null 默认约束 default(默认值) 检查约束 check() 外键约束 --逻辑约束 : 代码层面判断 --物理约束 : 在表结构中为字段添加约束--》不变与后期维护
--创建表的同时添加约束 ,字段后直接添加约束,默认的约束名 create table tb_user( userid number(5) primary key, username varchar2(30) check(length(username) between 4 and 20) not null, userpwd varchar2(20) not null check(length(userpwd) between 4 and 18), age number(3) default(18) check(age>=18), gender char(3) default('男') check(gender in('男','女')), email varchar2(30) unique, regtime date default(sysdate) ); --创建表(同时创建约束+指定名称) create table tb_user( userid number(5) constraint pk_user primary key, username varchar2(30) constraint xixihaha check(length(username) between 4 and 20) constraint xixihehe not null, userpwd varchar2(20) not null check(length(userpwd) between 4 and 18), age number(3) default(18) check(age>=18), gender char(3) default('男') check(gender in('男','女')), email varchar2(30) unique, regtime date default(sysdate) ); --创建表结构中,在所有字段声明的后面同意为字段添加约束 create table tb_user( userid number(5), username varchar2(30) constraint nn_user_name not null , userpwd varchar2(20) constraint nn_user_pwd not null , age number(3) default(18) , gender char(3) default('男'), email varchar2(30), regtime date default(sysdate), constraint pk_user_id primary key (userid), constraint ck_user_name check(length(username)between 4 and 20) , constraint ck_user_pwd check(length(userpwd) between 4 and 18), constraint ck_user_age check(age>=18), constraint ck_user_gender check(gender in('男','女')), constraint uq_user_email unique(email) ); --创建表(追加创建约束+指定名称) alter table tb_user add constraint pk_user_id primary key (userid); alter table tb_user add constraint ck_user_name check(length(username)between 4 and 20) ; alter table tb_user add constraint ck_user_pwd check(length(userpwd) between 4 and 18); alter table tb_user add constraint ck_user_age check(age>=18); alter table tb_user add constraint ck_user_gender check(gender in('男','女')); alter table tb_user add constraint uq_user_email unique(email); --外键约束的添加 --1)在字段后面直接指定外键约束,默认的约束名 create table tb_txt( txtid number(10), title varchar2(32) constraint nn_txt_title not null, txt varchar2(1024), pubtime date default(sysdate), userid number(5) references tb_user(userid) --指定了外键约束 ); --2)在字段的后面指定约束名添加外键约束 create table tb_txt( txtid number(10), title varchar2(32) constraint nn_txt_title not null, txt varchar2(1024), pubtime date default(sysdate), userid number(5) constraint pk_userid references tb_user(userid) --指定了外键约束 ); --3)表结构结束之前为指定字段添加外键约束 create table tb_txt( txtid number(10), title varchar2(32) constraint nn_txt_title not null, txt varchar2(1024), pubtime date default(sysdate), userid number(5), constraint fk_txt_ref_user_id foreign key(userid) references tb_user(userid) ); --4)表结构结束之后追加外键约束 alter table tb_txt add constraint fk_txt_ref_user_id foreign key(userid) references tb_user(userid); --已有表中拷贝结构 : 无法拷贝字段的约束 --只拷贝结构不拷贝数据 create table 表名 as select 字段列表 from 已有表 where 1!=1; create table haha_emp as select empno,ename,sal,deptno from emp where 1!=1; --拷贝结构同时拷贝数据 create table 表名 as select 字段列表 from 已有表 where 条件; create table hehe_emp as select empno,ename,sal,deptno from emp where deptno = 30; select * from tb_user; select * from tb_txt; insert into tb_user values(1111,'你好啊哈哈','1234',18,'女','xxxxx',sysdate); insert into tb_txt values(01,'微微一笑很倾城','xxxx',sysdate,1111); --加入注释 comment on table tb_user is '用户表'; comment on column tb_user.userid is '流水号,主键'; comment on column tb_user.username is '用户名'; comment on column tb_user.userpwd is '密码'; comment on column tb_user.age is '年龄'; comment on column tb_user.gender is '性别'; comment on column tb_user.email is '邮箱'; comment on column tb_user.regtime is '注册日期'; --删除 (先删除从表 再删除主表 ;同时删除约束) --如果删除的为主从表关系下的主表: --1)默认先删除所有从表,再删除主表 --2)删除主表的同时删除与从表之间的约束关系 cascade constraints --drop table 表名 (cascade constraints) drop table tb_txt cascade constraints; drop table tb_user cascade constraints; --修改alter --修改列名 alter table tb_user rename column username to uname; --约束的禁用与启用 ALTER TABLE tb_user disable constraint nn_user_name; ALTER TABLE tb_user enable constraint nn_user_name;