目录
一. 什么是数据库
数据库(Database)是按照来数据结构组织、存储和管理数据的仓库,它产生于距今六十多年前,随着信息技术和市场的发展,特别是二十世纪九十年代以后,数据管理不再仅仅是存储和管理数据,而转变成用户所需要的各种数据管理的方式。数据库有很多种类型,从最简单的存储有各种数据的表格到能够进行海量的大型数据库系统都在各个方面得到了广泛的应用。
在信息化社会,充分有效地管理和利用各类信息资源,是进行科学研究和决策管理的前提条件。技术支持是管理信息系统、办公自动化系统、决策支持系统等各类信息系统的核心部分,是进行科学研究和决策管理的重要技术手段。
二. 数据库的分类
数据库通常分为层次式数据库、网络式数据库和关系式数据库三种。而不同的数据库是按不同的数据结构来联系和组织的。而在当今的互联网中,最常见的数据库模型主要是两种,即关系型数据库和非关系型数据库。
1.关系型数据库:
它是将数据以关联关系或者二维表的形式存储的数据库。
如 oracle、mysql、db2、sql server、等;
2.非关系型数据库:
一般是以键值对方式存储数据的数据库。
如 redis、hadoop(hbase) 等
三. 了解Oracle
Oracle Database,又名Oracle RDBMS,或简称Oracle。是甲骨文公司的一款关系数据库管理系统。它是在数据库领域一直处于领先地位的产品。可以说Oracle数据库系统是目前世界上流行的关系数据库管理系统,系统可移植性好、使用方便、功能强,适用于各类大、中、小微机环境。它是一种高效率的、可靠性好的、适应高吞吐量的数据库方案。
注:数据库管理系统(Database Management System)是一种操纵和管理数据库的大型软件,用于建立、使用和维护数据库,简称DBMS
关系数据库管理系统(Relational Database Management System:RDBMS)是指包括相互联系的逻辑组织和存取这些数据的一套程序 (数据库管理系统软件)。关系数据库管理系统就是管理关系数据库,并将数据逻辑组织的系统。
注:常用的访问oracle的工具有SQL*Plus,EM,SQL Developer,PL Sql/developer,TOAD等。在本篇学习中使用的工具为PL Sql/developer 。
四.认识是SQL
SQL 是 Structured Query Language(结构化查询语言)的首字母缩写词,SQL 是数据库语言,通过 SQL可以实现与 Oracle 服务器的通信。可以执行CRUD等操作。
注:CRUD是指增加(Create)、检索(Retrieve)、更新(Update)和删除(Delete)
SQL分为一下几类
DDL(Data Definition Language):数据定义语言,用来定义表、列等;
如:创建数据表...
DML(Data Manipulation Language):数据操作语言,用来定义数据库记录(数据);
如:添加数据,修改数据,删除数据
DQL(Data Query Language):数据查询语言,用来查询记录(数据)。
如:查询数据
DTL (Data Transaction Language):数据事务语言,用来操作事务。
如:开启事务,提交事务
DCL (Data Control Language):数据控制语言。用来操作用户和权限
如:创建用户,授权。
五.学习SQL
1.简单查询
1.1 查询语句的语法
select 列名 , 列名 , .... from 表名;
select .... from .. : 为查询语句的关键字
select : 后面跟数据库中需要获取的数据
from : 后面跟数据库中你需要获取数据的表
例:
--查询emp表中员工的编号、姓名、工作、工资
select empno,ename,job,sal from emp;
--查询emp表中所有列的信息
select empno,ename,job,mgr,hiredate,sal,comm,deptno from emp;
如果要查询表中所有列的信息,那么select和from之间的列名可以用*来表示。
注意:*号的执行效率比写列名时的执行效率低,(*在执行sql语句时,oracle会去查数据库中的数据字典,查询这个张表都有哪些列,然后查出这张表的所有列的数据)。建议查询时查询所需数据字段,从而提高响应时间。
1.2 注释
单行注释:--
多行注释:以 /* 开始,以 */ 结尾
1.3 SQL中的别名
别名语法:select 列名 as 别名 ,...... from 表名
对象名 as 别名 :利用as在后面添加别别名
对象名 别名 :不用as直接添加别名
例:
select empno as 员工编号,ename 姓名,job 工作,mgr 上级编号,hiredate 入职日期,sal 工资,comm 佣金,deptno 部门编号 from emp;
注意:给表、视图取别名时不能加as ,给字段取别名时也可以不添加 as
2.排列分组
2.1 排列
语法:select 列名,列名,..,列名 from 表名 where 条件表达式 order by 排序列的列名 asc|desc;
关键字 asc|desc: asc表示升序,desc表示降序
例:
--查询员工信息,按照员工的工资升序排序
select * from emp order by sal asc; ---如果是升序排序,asc可以省
select * from emp order by sal;
--查询员工信息,按照员工编号降序排序
select * from emp order by empno desc;
注:order by 后面可以跟多个排序列,跟多个排序列时,它的含义:按照第一排序列(紧跟前order by 关键字的列)排序,如果第一个排序字段的值相同时,它会按照第二个排序字段进行排序
2.2 聚合函数
聚合函数:对一组值执行计算,并返回单个值
常用聚合函数如下:
count(列名|*|常数):它求记录数(数据条数)
max(列名):取最大值
min(列名):取最小值
avg(列名):取平均值
sum(列名):求和
例:
--查询员工表中的员工人数
select count(empno) from emp; count(主键列或索引列)
select count(*) from emp; count(*)
select count(1) from emp; count(常数)
select count(sal) from emp; count(普通列)
它们执行效率从上到下,依次降低
--查询emp表中的部门数
select count(deptno) from emp; (部门数据有重复)
select deptno from emp; (查询表中部门其中有重复)
distinct:去重关键字,跟在列的最前面
select distinct deptno from emp; (查询表中部门其中无重复)
select count(distinct deptno) from emp; (部门数据不重复)
select empno,distinct deptno from emp; --这个sql语句是错误的
select distinct empno,deptno from emp;
注意:distinct后面跟多个列时,判断重复数据,所有列的值完全相同时,它才会认为是重复数据
--查询工资总和
select sum(sal) from emp;
--查询员工的平均工资
select avg(sal) from emp;
--查询10号部门的最高工资
select max(sal) from emp where deptno=10;
--查询最低工资
select min(sal) from emp;
2.3 分组
语法:select 列名,列名,...,列名 from 表名 where 条件 group by 分组列 order by 排序列 asc|desc
group by:分组的关键字,后面跟分组列名,可以是一个分组列,也可以是多个列
例:
--查询各个部门的部门编号和部门的平均工资
select deptno,avg(sal) from emp group by deptno;
select empno,min(sal),max(sal),avg(sal),sum(sal),count(*) from emp group by empno;
--查询各个部门的员工人数
select deptno,count(empno) from emp group by deptno;
select job,deptno,count(*) from emp group by job,deptno;
注意:先分组后排序,group by 后面跟多个列时,只有当多个列的值同时相等时,它才会分为同一个组;
2.4 having条件的使用
语法:select col_name,col_name,...,col_name from 表名where 条件group by 分组列having 条件order by 排序列;
having:它是对分组后的数据进行筛选,条件表达式中可以使用聚合函数
例:
--查询各个部门的部门编号和部门的平均工资
select deptno,avg(sal) from emp group by deptno;
--求平均工资大于2000的部门编号和平均工资
select deptno,avg(sal) from emp group by deptno having avg(sal)>2000;
注:where和having的异同
where:条件,where后面跟的条件比having后的条件先执行,条件中不允许使用聚合函数。having:条件中可以使用聚合函数,一般having和group by联用。在sql语句中尽量用where 代替 having 这样可以提高查询效率。在查询过程中先分组在条件最后选择排序
3.集合,联合查询
3.1 集合
集合:每一个sql查询的结果就是一个集合 如:(1,3,4,65,234,123,12)
select * from emp;
并集:取两个集合中所有元素
union all:表示取两个集合的并集,不删除重复元素
union :取两个集合的并集,删除重复的元素
例:
--查询员工工资大于1000的员工信息
select * from emp where sal>1000;
--查询员工工资小于3000的员工信息
select * from emp where sal<3000;
等价于:
select * from emp where sal>1000
union all
select * from emp where sal<3000;
等价于:
select * from emp where sal>1000
union
select * from emp where sal<3000;
注:union、union all:union all执行效率高,union执行效率低(先进行union all把两个集合合并,之后对合并后的数据进行排序,去掉重复元素),故一般多使用union all 提升查询相应效率。
交集:取两个集合重叠部分的元素
关键字 intersect:表示交集
例:
--查询工资在1000到3000之间的员工信息
select * from emp where sal>1000 and sal<3000;
等价于:
select * from emp where sal>1000
intersect
select * from emp where sal<3000;
差集:第一个集合的所有元素减去两个集合重叠部分的元素
Minus:表示差集
例:
select * from emp where sal>1000
minus
select * from emp where sal<3000;
等价与:
select * from emp where sal>=3000;
集合运算,关键字前后的两个sql表示的结果集要完全相同。
3.2 联合查询
联合查询有以下几种:交叉连接(笛卡尔积连接)、内连接、自连接、外连接(全连接、左外连接、右外连接)、自然连接
3.2.1 交叉连接(笛卡尔积连接)
将会返回被连接的两个表的笛卡尔积,返回结果的行数等于两个表行数的乘积.
语法:
select 列名,列名,... from a表 cross join b表; cross join (关键字)
例:
select * from emp;
select * from dept;
select e.*,d.deptno dno,d.dname,d.loc from emp e cross join dept d;
select e.*,d.deptno dno,d.dname,d.loc from emp e,dept d;
3.2.2 内连接
内连接:是把两个表中符合条件的数据连接为一条数据,如果哪个表中存在不符合连接条件的数据,那么这些数据就会被过滤掉(不显示)
语法:
select 列名,...,列名 from a表 inner join b表 on 连接条件
关键字 inner join:中的inner可以省略不写
例:
--查询员工信息及他的部门信息
select e.*,d.* from emp e inner join dept d on e.deptno=d.deptno;
select e.*,d.* from emp e join dept d on e.deptno=d.deptno;
3.3.3 自连接
自连接是一个特殊的内连接,内连接一般是两个表的连接,自连接将一个表和它自已进行连接
例:
--查询员工信息,并显示它的上级姓名
select e1.*,e2.ename 上级姓名 from emp e1 join emp e2 on e1.mgr=e2.empno
select e1.*,e2.ename from emp e1,emp e2 where e1.mgr=e2.empno;
3.2.4 不等连接
不等连接:连接条件是不等条件,(大于、小于、不等于)
例:
--查询员工信息,并显示员工的工资等级
select * from salgrade;
select e.*,s.grade,s.losal,s.hisal from emp e join salgrade s on e.sal between s.losal and s.hisal;
3.2.5 全连接
全连接:它会查出两个表中的所有数据,
(1)如果两个表中的数据都符合连接条件,那么它会和内连接一样,将符合条件的数据连接为一条记录
(2)如果第一表中的一条数据,在第二张表中没有找到和它对应的记录(第二张表没有和第一张表这条数据符合连接条件),
那么它同样会显示第一张表的这条记录,同时它对应的第二张表数据的位置会显示为空
(3)同理,如果第二张的一条记录,在第一张表中没有找到符合连接条件的数据,那么同样会显示,在显示第一张表数据的位置显示为空
语法:
select 列名,列名,列名,.... from 表 A full outer join 表B on 连接条件;
关键字 full outer join :中的outer可以省略
例:
--查询所有部门和员工信息
select e.*,d.* from emp e full outer join dept d on e.deptno=d.deptno;
3.2.6 左外连接
查出左表(left outer join关键字前面的表)的所有数据,根据连接条件去右表中找对应的数据,如果找到变显示出来,如果找不到就显示空
select 列名,列名,... from 表A left outer join 表B on 连接条件
关键字 left outer join :其中outer可以省略
例:
--查询所有部门信息,以及各部门下的员工信息
select d.*,e.* from dept d left join emp e on d.deptno=e.deptno;
select d.*,e.* from dept d,emp e where d.deptno=e.deptno(+);
注意:用(+)表示的左连接或者右连接,如果是左连接,那么符号加在右表的关系列上,如果是右连接,那么符号加在左表的关系列上
例:
--左连接
select d.*,e.* from dept d,emp e where e.deptno(+)=d.deptno;
--右连接
select d.*,e.* from dept d,emp e where d.deptno(+)=e.deptno;
3.2.7 右外连接
语义:它会查出右表的所有数据,根据连接条件去左表查找对应的数据,如果找到就显示,如果找不到就显示为空语法:
select 列名,列名,列名,... from 左表 right outer join 右表 on 连接条件
关键字 right outer join:其中outer可以省略
例:
--查询员工信息,并显示它的部门信息
select d.*,e.* from dept d right outer join emp e on d.deptno=e.deptno;
select d.*,e.* from dept d,emp e where d.deptno(+) = e.deptno;
3.2.8 自然连接
自然连接是在两张表中寻找那些数据类型和列名都相同的字段,然后自动地将他们连接起来,并返回所有符合条件按的结果。
语法:
select col_name,... from table_a natural join table_b;
select col_name,.... from table_a natural join table_b using(关系列)
例:
select * from emp natural join dept; --自然连接
select * from emp join dept using(deptno); --自然连接using用来指定关系列
4.子查询
子查询指一个查询语句嵌套在另一个查询语句中
4.1 from后面的子查询
例:
--查询员工的姓名和他上级的姓名
select e.*, e2.empno, e2.ename mname, e2.job, e2.sal, e2.deptno from emp e, emp e2
where e.mgr = e2.empno(+);
select e.empno,
e.ename,
e.job,
e.mgr,
e.hiredate,
e.sal,
e.comm,
e.deptno,
d.empno,
d.ename,
d.job,
d.mgr,
d.hiredate,
d.sal,
d.comm,
d.deptno
from emp e,emp d
where e.mgr=d.empno;
select ename, mname
from (select e.*, d.empno, d.ename mname, d.job, d.sal, d.deptno
from emp e, emp d
where e.mgr = d.empno(+));
4.2 where后面的子查询
4.2.1 单行子查询
单行子查询:子查询的sql语句只查出一条记录
例:
--查询工资大于10号部门平均工资的员工信息
--查询10号部门的员工平均工资
select avg(sal) from emp where deptno=10;
select * from emp where sal>(select avg(sal) from emp where deptno=10);
4.2.2 多行子查询
多行子查询:子查询的sql语句查出若干条记录
in、not in、exists、not exists、all、any
--查询工资比20号部门所有人工资都高的员工信息
1)用单选子查询来完
--查询20号部门的最高工资
select max(sal) from emp where deptno=20;
select * from emp where sal>( select max(sal) from emp where deptno=20);
2)>all
--20号部门的员工工资是一个集合
select sal from emp where deptno=20;
select * from emp where sal>all(select sal from emp where deptno=20);
4.3 exists、not exists
--查询有员工的部门信息
select * from dept;
--根据部门编号查询员工人数
select count(*) from emp where deptno=10;
select * from dept d where (select count(*) from emp where deptno=d.deptno)!=0;
注:exists后面跟子查询,如果子查询能查出数据,那么条件是真的,如果子查询查不出结果,条件不成立
select * from dept d where exists(select * from emp where deptno=d.deptno);
--查询没有有员工的部门信息
select * from dept d where not exists(select * from emp where deptno=d.deptno);
4.4 having 后的子查询
--查询各个部门的部门编号和员工人数,要求部门的平均工资大于30号部门的平均工资
select deptno,count(*),avg(sal) from emp group by deptno having avg(sal)>1500;
--查询30号部门的平均工资
select avg(sal) from emp where deptno=30;
select deptno,count(*) from emp group by deptno having avg(sal)>(select avg(sal) from emp where deptno=30);
4.5 select 和from 之间的子查询
select empno,ename,(select 1 from dual) from emp;
注意:select 和from之间的子查询,子查询的结果只能是单行单列
原始排序:
select e.*,(select count(*) from emp where sal>e.sal) from emp e order by 9;
5.分页sql
伪列:rownum 它是oracle数据库内置列,任何表都可以使用,它作用是显示表中数字的行号
select * from emp;
select emp.*,rownum from emp;
select t.*,rownum r from (select * from emp order by sal) t;
--查询工资最低的5名员工信息
select t.*,rownum r from (select * from emp order by sal) t where rownum<=5;
--注意如果给伪列加条件,小于一个值是可以,不能让它大于某个值
select t.*,rownum r from (select * from emp order by sal) t where rownum>=2; --伪列不能直接大于一个值
select t.*,rownum r from (select * from emp order by sal) t where rownum=5; --伪列不能直接等于一个不等于1的值
select t.*,rownum r from (select * from emp order by sal) t where rownum=1; --伪列可以直接等于1
使用rownum的分页sql,rownum伪列的序号,只连续的不考虑值相等的情况(值相同序号不相同)
--查询5到10名的员工信息
select * from (select t.*,rownum r from (select * from emp order by sal) t) t2 where t2.r between 5 and 10;--包三层查询
row_number():需要和over分析函数联用,排序的序号和rownum伪列相同,连续序号,不考虑值相等的情况(值相同序号不相同)
dense_rank():可以用来做排序,它序号连续,考虑重复数据,如果值相等序号就相同
rank():可以用来做排序,它序号不连续,考虑重复数据,如果值相等序号相同
over(partition by 分组列 order by 排序列):over子句中的分组partition by和group by的分组不同,它不会把数据聚合成一条,在over子名中可以省略
select e.*,row_number()over(order by sal desc) r from emp e;
select e.*,dense_rank()over(order by sal desc) r from emp e;
select e.*,rank()over(order by sal desc) r from emp e;
select e.*,row_number()over(partition by deptno order by sal desc) r from emp e;
select e.*,dense_rank()over(partition by deptno order by sal desc) r from emp e;
select e.*,rank()over(partition by deptno order by sal desc) r from emp e;
使用row_number(),rank(),dense_rank()的分页sql,只需要一层子查询
select * from (select e.*,row_number()over(order by sal) r from emp e) t where t.r between 5 and 10;
6.case when语句
语法:
case
when 条件表达式1 then
值
when 条件表达式2 then
值
when 条件表达式3 then
值
...
else
默认值
end
语义:如果表达式成立,那么整个语句值为表达式,then后面的值,如果所有表达式都不成立,会取else后的默认值,else语句可以省略
select * from student;
select count(*) from student where ssex='男';
select s.*,(select count(*) from student where ssex='男') 男生人数,(select count(*) from student where ssex='女') 女生人数 from student s;
使用case when统计男生人数
select sum(case when ssex='男' then 1 else 0 end) 男生人数,sum(case when ssex='男' then 0 else 1 end) 女生人数,sum(case when ssex='女' then 1 else 0 end) 女生人数 from student s;