分类 产品 特点
小型 access、foxbase 负载量小,用户大概 100 人以内 (留言板、信息管理系统);成本在千元之内,对安全性要求不高
中型 sqlservler、mysql 负载量,日访问在 5000~10000;成本在万元以内(商务网站);满足日常安全需求
大型 sybase、db2、oracle 海量负载,可以处理海量数据( sybase
在设计数据库时,存在行业的标准,这个标准也称为条件,即范式 NormalForm。一般遵循三个条件即可,也就是三范式(3NF)
1.每一列都是不可分割的基本数据项。
2.第二范式就是非主属性非部分依赖于主键。
3.第三范式就是属性不依赖于其它非主属性。
查询的结构如下:
select distinct * | 字段 | 表达式 | 函数 as 别名
from 表 表别名
where 过滤行记录条件
group by 分组字段列表
having 过滤组
order by 字段列表 asc | desc
1)、from 2)、where 3)、group 4)、having 5)、select 6)、order by
简单查询:
--注释
--1)
--查询|检索|获取 所有员工的所有信息
select * from emp;
--2)
--查询所有的员工名字
select ename from emp;
--3)
--查询所有的员工编号和员工名称,员工上级的编号
select empno,ename,mgr from emp;
--4)
--查询所有部门部门编号
select deptno from dept;
--5)
--查询出所有员工所在的部门的部门编号,对查询数据进行去重(非字段去重) distinct
select distinct deptno from emp;
--6)
--查询出所有存在员工的部门的部门编号,以及员工名称
select deptno,ename from emp;
--7)
--查询表达式,结果是表达式的值,显示的字段名就是表达式,计算值
select 1+1 from emp;
select 'a' from emp;
--8)
--给字段取别名 select 字段1 (as) 别名1,字段2 别名2 from 表名 别名; 表的别名不能加as
--查询所有员工的名称(别名为:名字),员工编号(编号)
--别名默认变大写,别名中的内容原封不动出现 ""->中的内容原封不动出现
select 123+456 "get sum" from emp;
select empno as 员工编号,ename "员工 姓名" from emp;
--9)
--字符串 '' 原封不动显示""
select distinct '哈哈' 笑 from emp e;
--10)
--字符串拼接 java中使用+ 这里使用||
--查询 ab--cd 表达式
select distinct 'ab-'||'-cd' from emp;
--11)
--伪列 : 不存在的列就是伪列 比如:表达式,字符串
--12)
--虚表: 在oracle中不存在的表,也可以说是这个表中没有任何数据,没有任何字段 --oracle中的虚表:dual
--虚表的作用:可以不使用distinct就可以去重的效果,因为里面没有数据,不会出现多行
select * from dual;
13)
--给每一个员工在原来的基础上+100块钱奖金
--null 空
--null与数字运算,结果还为null
--null与字符串运算,结果原串
--nvl(参数1,参数2) 处理null使用 如果参数1为null,最终结果参数2,如果参数1不为null,最终的结果就是参数1
select comm 原奖金,comm||'100' 新奖金 from emp;
select comm 原奖金,nvl(comm,0)+100 新奖金 from emp
条件查询一
select *|表达式|字符串|伪列|字段1 别名1,字段2 as 别名2... from 表名 别名|结果集 where 行过滤条件;
--执行流程: from-->where-->select确定结果集
-- 查询20部门的员工信息
select * from emp where deptno=20;
-- > < >= <= = != <>
-- 查询工资大于1000的员工的姓名 工作岗位 工资 所属部门编号
select ename,job,sal,deptno from emp where sal=1000;
-- 查询不在20部门工作的员工信息
select * from emp where deptno != 20;
select * from emp where deptno <> 20;
--where 中不能使用字段的别名
-- 查询员工的年薪大于20000的 员工名称、岗位 年薪
select ename 姓名,job 岗位,(sal+nvl(comm,0))*12 sum from emp where ((sal+nvl(comm,0))*12)>20000;
select ename 姓名,job 岗位,(sal+nvl(comm,0))*12 sum from emp;
select 岗位, sum
from (select ename 姓名, job 岗位, (sal + nvl(comm, 0)) * 12 sum from emp)
where sum > 20000;
-- 查询 any(任意一个) some(任意一个) all(所有)
select * from emp where deptno = any(10,20);
select * from emp where deptno = some(10,20);
select * from emp where sal> all(1500,2000); --薪资>2000的就可以
-- 查询 工种不为’SALESMAN’的员工信息 (注意 内容区分大小写)
select * from emp where not job ='SALESMAN';
--or或 and并且|都 not取反
-- -检索 工资 1600, 3000员工名称 岗位 工资
select ename,job,sal from emp where sal=1600 or sal=3000;
select ename,job,sal from emp where not (sal=1600 or sal=3000);
-- 工资在2000到3000之间的员工信息
--between 小范围值 and 大范围的值 两者之间 <= >=
select * from emp where sal between 1600 and 3000;
--存在佣奖金的员工名称
select ename,comm from emp where not comm is null;
select ename,comm from emp where comm is not null;
--不存在奖金的员工名称
select ename,comm from emp where comm is null;
--集合
--Union,并集(去重) 对两个结果集进行并集操作,不包括重复行同时进行默认规则的排序;
--Union All,全集(不去重) 对两个结果集进行并集操作,包括重复行,不进行排序 ;
--Intersect,交集(找出重复) 对两个结果集进行交集操作,不包括重复行,同时进行默认规则的排序;
--Minus,差集( 减去重复 ) 对两个结果集进行差操作,不包括重复行,同时进行默认规则的排序
--查询工资大于1500 或 含有佣金的人员姓名
select ename,sal,comm from emp where sal>1500 or comm is not null;
--并集
select ename,sal,comm from emp where sal>1500
Union
select ename,sal,comm from emp where comm is not null;
--全集
select ename,sal,comm from emp where sal>1500
Union all
select ename,sal,comm from emp where comm is not null;
--查询显示不存在雇员的所有部门号。
--求出所有的部门号
select deptno from dept;
--有员工的部门号
select distinct deptno from emp;
--求差集,大范围的在上面
select deptno from dept
Minus
select distinct deptno from emp;
-- 查询显示存在雇员的所有部门号。
select deptno from dept
Intersect
select distinct deptno from emp;
--模糊匹配 like %任意任意字符 _一个任意字符 一起使用
--查询员工姓名中包含字符A的员工信息
select * from emp where ename like '%A%';
--查询员工姓名中第二个字母为A的员工信息
select * from emp where ename like '_A%';
--escape('单个字符')指定转义符
--查询员工姓名中包含字符%的员工信息
select * from emp where ename like '%B%%' escape('B');
--当执行插入数据,删除数据,修改的时候,默认开启事务
--可提交 commit
--可回滚 rollback
--多个人中任意一个值就可以
select * from emp where sal=1600 or sal=3000 or sal=1500;
select * from emp where sal in(1500,1600,3000);
--按照奖金升序排序,如果存在null值,所有的奖金null值的数据最先显示
select empno,ename,sal,comm from emp where deptno in (10,30) order by comm asc nulls first;
条件查询二嵌套查询
--部门名称为 SALES 或 ACCOUNTING 的雇员信息
--查询的数据: 员工信息*
--来源: emp
--条件: 部门名称=SALES 或 ACCOUNTING;
--子查询
select *
from emp
where deptno in
(select deptno from dept where dname in ('SALES', 'ACCOUNTING'));
-- 查询工资等级为 2的员工信息
select *
from emp
where sal between (select losal from salgrade where grade = 2) and
(select hisal from salgrade where grade = 2);
-- 查询 销售部(SALES) 中 工资大于1500的员工信息
select *
from emp
where sal > 1500
and deptno = (select deptno from dept where dname = 'SALES');
select *
from (select *
from emp
where deptno = (select deptno from dept where dname = 'SALES'))
where sal > 1500;
-- 查询工资比SMITH高的同一部门的员工信息
--条件: sal>SMITH的薪资 and deptno = SMITH的部门编号
select *
from emp
where sal > (select sal from emp where ename = 'SMITH')
and deptno = (select deptno from emp where ename = 'SMITH');
--exists 存在即保留,存在即合法
select *
from emp
where exists (select deptno from dept where dname = 'SALES');
select *
from emp
where exists (select deptno
from dept
where dname in ('SALES', 'ACCOUNTING')
and emp.deptno =dept.deptno);
--20部门的员工信息
select *
from emp e
where not exists (select deptno
from dept d
where dname in ('SALES', 'ACCOUNTING')
and e.deptno = d.deptno);
--有奖金的员工信息
select empno, ename, sal,comm
from emp e1
where exists (select empno, ename, sal, comm
from emp e2
where comm is not null
and e1.empno = e2.empno);
--与有奖金的员工统一部门的所有员工的员工信息
select empno, ename, sal,deptno
from emp e1
where exists (select empno, ename, sal, comm,deptno
from emp e2
where comm is not null
and e1.deptno = e2.deptno);
函数有内置函数和自定义函数,这里先简单地介绍一下内置函数,内置函数又可分为单行函数和多行函数。
单行函数:一条记录返回一个结果。
1、日期函数
sysdate/current_date 以date类型返回当前的日期
add_months(d,x) 返回加上x月后的日期d的值
LAST_DAY(d) 返回的所在月份的最后一天
months_between(date1,date2) 返回date1和date2之间月的数目
next_day(sysdate,‘星期一’) 下周星期一
-- 当前时间
select sysdate from dual;
select current_date from dual;
select ename,sysdate from emp;
-- 加减日期
-- 2天以后是几号
select sysdate+2 from dual;
-- 所有员工入职的3天前是几号
select ename,hiredate,hiredate-3 from emp;
-- 查询所有员工的试用期期到期(转正的日期) 3个月试用期
select ename,hiredate 入职日期,hiredate+30*3 转正日期 from emp;
--add_months() 月份相加
select ename,hiredate 入职日期,add_months(hiredate,3) 转正日期 from emp;
-- 查询所有员工到目前为止一共工作了几个月
select ename,months_between(sysdate,hiredate) from emp;
-- 查询当前月的最后一天
select last_day(sysdate) from dual;
select last_day(hiredate) from emp;
-- 下一个星期三是几号
select next_day(sysdate,'星期一') from dual;
--日期对象与字符串之间的转问题
-- to_date('字符串','识别日期字符串模板')
-- 设定一个特定的时间(用一个特定的时间字符串转换为日期)
select to_date('2019-07-30 10:11:13','yyyy-mm-dd hh24:mi:ss')+3 from dual;
select to_date('2019年07月30日 10:11:13','yyyy"年"mm"月"dd"日" hh24:mi:ss') from dual;
-- 将日期转为特定格式的字符串 to_char()
select to_char(sysdate,'yyyy"年"mm"月"dd"日" hh24:mi:ss') from dual;
2、转换函数
to_date(c,m) 字符串以指定格式转换为日期
to_char(d,m) 日期以指定格式转换为字符串
--日期对象与字符串之间的转问题
-- to_date('字符串','识别日期字符串模板')
-- 设定一个特定的时间(用一个特定的时间字符串转换为日期)
select to_date('2019-07-30 10:11:13','yyyy-mm-dd hh24:mi:ss')+3 from dual;
select to_date('2019年07月30日 10:11:13','yyyy"年"mm"月"dd"日" hh24:mi:ss') from dual;
-- 将日期转为特定格式的字符串 to_char()
select to_char(sysdate,'yyyy"年"mm"月"dd"日" hh24:mi:ss') from dual;
3、其他函数 (保证类型兼容)
nvl(string1,string2) 如果string1为null,则结果为string2的值
decode(condition,case1,express1,case2 , express2,….casen , expressn, expressionm)
case when then else end
decode 判断decode(判定字段,校验字段值1,结果1,校验字段2,结果2。。,默认值)
--给每个部门后后面添加一个伪列,如果10部门,伪列显示为十,二十,三十...
select deptno,dname,decode(deptno,10,'十',20,'二十',30,'三十',40,'四十') 中文名字 from dept;
-- 给20部门的所有员工都涨薪10%,显示出员工的名称, 原来的薪水, 所属部门编号, 涨薪后的薪水
select ename,sal 原薪水,deptno 部门编号,decode(deptno,20,sal*1.1,sal) 涨薪后的薪水 from emp;
-- 10部门涨薪10%, 20涨薪20%,30降薪1% , 40部门翻倍3倍
SELECT ENAME,
SAL 原薪水,deptno 部门编号,decode(deptno, 10, sal * 1.1, 20, sal * 1.2, 30, sal * 0.99, 40, sal * 3) 涨薪后的薪水
from emp;
select ename,
sal 原薪水,deptno 部门编号,(case deptno when 10 then sal * 1.1 when 20 then sal * 1.2 when 30 then sal*0.99 when 40 then sal * 3end) 涨薪后的薪水
from emp;
组函数
组函数|多行函数|聚合函数,即多条记录返回一个结果。
count :统计记录数 count() -->* 或一个列名
max min: 最大值 最小值
sum:求和
avg:平均值
分组: group by , 将符合条件的记录 进一步的分组。
过滤组:having , 过滤组信息 ,表达式 同 where 一致。
--所有有员工存在的部门编号
select distinct deptno from emp;
select deptno from emp group by deptno;
--10,30,部门的每个部门最高薪资
select max(sal) from emp group by deptno;
--先过滤再分组
select max(sal) from emp where deptno in(10,30) group by deptno ;
--先分组再过滤
select max(sal),deptno from emp group by deptno having deptno in(10,30);
--如果有分组,select后只能跟分组字段和组函数
select * from emp;
-- 求出平均工资高于2000的部门编号和平均工资
select deptno,avg(sal) from emp group by deptno having avg(sal)>2000;
--按 部门岗位(job) 查询 平均工资
select avg(sal) from emp group by job;
--按 岗位查询 平均工资,且平均工资大于2000的岗位
select avg(sal),job from emp group by job having avg(sal)>2000;
--求平均薪资最高的部门编号
select deptno from emp group by deptno having avg(sal)= (select max(avg(sal)) from emp group by deptno);
--求每个部门的平均薪资
select avg(sal),deptno from emp group by deptno;
--求最高部门的平均薪资
select avg(sal) from
--使用一条sql语句,查询出没门课程分数都>80分的学生名字
--查询的数据: 学生名字 name
--数据的来源: tb_student
--条件: 没门分数都要>80 and 每一个人的总课程数=3
select name
from tb_student
group by name
having min(score) > 80 and count(1) = (select count(distinct course) from tb_student);
--每个人如果最分数都>80,证明所有成绩都>80
select name from tb_student group by name having min(score)>80;
--一共有几门课程
select count(distinct course) from tb_student;
select name from tb_student group by name having count(1) =3;
--行转列
select name,
min(decode(course, '语文', score)) "语文",
max(decode(course, '数学', score)) "数学",
avg(decode(course, '英语', score)) "英文"
from tb_student
group by name;
select 语文,数学,nvl(英文,0) from (select name,
min(decode(course, '语文', score)) "语文",
max(decode(course, '数学', score)) "数学",
avg(decode(course, '英语', score)) "英文"
from tb_student
group by name);
rowid:相当于表中每一个条记录的地址,数据插入到表中的时候就已经存在,后续不会改变。
没有主键,没有唯一的字段,可以存在多条数据重复,想要达到去重,可以使用rowid。
--查到唯一的不重复的每一条数据,重复的数据只显示一条
select name,course,score,min(rowid) from tb_student group by name,course,score;
select * from tb_student where rowid in (select min(rowid)
from tb_student
group by name, course, score);
--查询要删除的数据
select * from tb_student where not rowid in (select min(rowid)
from tb_student
group by name, course, score);
--删除这些数据
delete from tb_student
where not rowid in
(select min(rowid) from tb_student group by name, course, score);
rownum:结果集中数据的序号。
利用rownum可以达到分页查询的效果。
--根据薪资进行升序排序,达到分页的效果一页显示4条数据 num=4,显示第二页的数据i=2
select empno, ename, sal,n
from (select empno, ename, sal, rownum n
from (select empno, ename, sal, rownum from emp order by sal))
where n >= 5
and n <= 8;
表之间的连接可以用92语法和99语法。
92语法:
--笛卡尔积
select * from emp,dept order by sal;
--等值连接 可以是两个表中的相同字段做连接,可以是不同字段做连接,但是类型要保持一致
select * from emp,dept where emp.deptno=dept.deptno;
select * from emp,dept where emp.ename=dept.dname;
--非等值连接
--查询每个员工的信息以及这个员工的薪资等级
select * from emp,salgrade where sal between losal and hisal;
--查询2500薪资的等级
select grade from salgrade where 2500 between losal and hisal;
--查询 每一个的员工的员工信息,薪资等级,部门信息
select * from emp,dept,salgrade where emp.deptno=dept.deptno and sal between losal and hisal;
--查询 30部门员工的 每一个的员工的员工信息,薪资等级,部门信息
--92语法中,相同的字段一定要指明字段的出处
select *
from emp, dept, salgrade
where dept.deptno = 30
and emp.deptno = dept.deptno
and sal between losal and hisal;
--30部门的员工信息及部门信息
--先连接后过滤
select empno,ename,e.deptno,dname from emp e,dept d where e.deptno=d.deptno and e.deptno=30;
--先过滤后连接,效率较高
select empno, ename, e.deptno, dname
from (select * from emp where deptno = 30) e,
(select * from dept where deptno = 30) d;
--查询所有有上级的员工信息及其上级经理人信息 自连接
--员工表 e1和经理人表 e2
select * from emp e1,emp e2 where e1.mgr=e2.empno;
--查询所有的员工信息及其上级经理人信息 所有员工都应该显示
--想要无论是否满足连接条件,都要显示其中数据的表->主表
--外链接
--做为主表的表中的数据全部显示
--在连接条件的位置,在主表对面的表的连接条件后添加(+)
-- emp e1,emp e2 主表的位置确定,主表在左边叫做左连接,主表在右边,叫做右连接
select * from emp e1,emp e2 where e1.mgr=e2.empno(+); --左连接
select * from emp e2,emp e1 where e1.mgr=e2.empno(+); --右连接
99语法:
交叉连接 cross join —>笛卡尔积
自然连接(主外键、同名列) natural join -->等值连接
join using连接(同名列) -->等值连接
[inner]join on 连接 -->等值连接 非等值 自连接 (解决一切) 关系列必须区分
left|right [outer] join on|using -->外连接
full join on|using -->全连接 满足直接匹配,不满足 相互补充null ,确保 所有表的记录 都至少
出现一次
--cross join 笛卡尔积
select * from dept cross join emp;
--查询员工的信息以及所在部门信息
--自然连接 natural join 自动匹配两张表中主外键关系的字段,或同名字段,做等值连接
select dname,deptno,empno,ename from dept inner natural join emp;--注意:自然连接同名字段不能出现限定词
--join..using(等值连接的字段) 指定使用哪一个字段做等值连接
select dname,deptno,empno,ename from dept inner join emp using(deptno);
--显示用户信息和薪资等级
--表1 join 表2 on 连接条件-->等值|非等值
select * from emp join salgrade on sal between losal and hisal;
select emp.deptno,ename from emp inner join dept on emp.deptno=dept.deptno;
--所有部门的 部门名称,员工数
--外链接 左外left join 右外right join
--作为主表的数据全部显示 主表dept,在左边所以是左连接
--计算人数的结果集应该来自与emp员工表中,结果集与部门表做连接,连接条件部门编号
select dname,nvl(n,0) from dept left join (select deptno,count(1) n from emp group by deptno) e on dept.deptno=e.deptno;
--全连接 两张表都作为主表
select *
from (select 1 no, 'a' "name"
from dual
union
select 2 no, 'b' "name"
from dual) s1
full join (select 1 no, 'c' "name"
from dual
union
select 3 no, 'd' "name"
from dual) s2
on s1.no = s2.no;
视图:建立在表|结果集|视图上的虚拟表,有以下作用:
1、简化:select 查询语句
2、重用:封装select语句 命名
3、隐藏:内部细节
4、区分:相同数据不同查询
注意:不是所有的用户都有创建视图的权限。
创建视图:
create or replace view 视图名 as select语句 [with read only]
删除视图:
drop view 视图名
数据库的对象之一,对象本身是需要维护的
索引本身是透明的,是否创建对于数据库表的本身,和使用上没有任何影响
对大量数据,常用于查询,会提高执行效率,执行速度
对添加索引的字段大量的做增删改,需要更新维护索引对象,降低效率
相当于字典的目录
oracle会自动为主键添加索引
创建索引:
create index 索引名 on表名 (字段列表…)
删除索引:
drop index 索引名