SELECT [DISTINCT] {*,column alias,…}
FROM table alias
Where 条件表达式
查询雇员表中部门编号是10的员工
select empno,ename,job from emp where deptno = 10;
dinstinct 去除重复数据
select distinct deptno from emp;
去重也可以针对多个字段,多个字段值只要有一个不匹配就算是不同的记录
select distinct deptno,sal from emp;
在查询的过程中可以给列添加别名,同时也可以给表添加别名
select e.empno 雇员编号,e.ename 雇员名称,e.job 雇员工作 from emp e where e.deptno = 10;
给列起别名可以加as,也可以不加
select e.empno as 雇员编号,e.ename as 雇员名称,e.job as 雇员工作 from emp e where e.deptno = 10;
给列起别名,如果别名中包含空格,那么需要将别名整体用“”包含起来
select e.empno as "雇员 编号",e.ename as "雇员 名称",e.job as "雇员 工作" from emp e where e.deptno = 10;
=,!=,<>,<,>,<=,>=,any,some,all
select * from emp where deptno = 20;
any,取其中任意一个
select sal from emp where sal > any(1000,1500,3000);
some,some跟any是同一个效果,只要大于其中某一个值都会成立
select sal from emp where sal > some(1000,1500,3000);
all,大于所有的值才会成立
select sal from emp where sal > all(1000,1500,3000);
is null,is not null
is null,在sql的语法中,null表示一个特殊的含义,null != null,不能使用=,!=判断,需要使用is ,is not
select * from emp where comm is null;
select * from emp where comm is not null;
select * from emp where null is null;
between x and y
between x and y,包含x和y的值
select * from emp where sal between 1500 and 3000;
select * from emp where sal >=1500 and sal <=3000;
in(list),not in(list)
需要进行某些值的等值判断的时候可以使用in和not in
select * from emp where deptno in (10, 20);
select * from emp where deptno = 10 or deptno = 20;
select * from emp where deptno not in(10, 20);
select * from emp where deptno != 10 and deptno != 20;
exists(sub-query)
当exists中的子查询语句能查到对应结果的时候,意味着条件满足,相当于双层for循环
现在要查询部门编号为10和20的员工,要求使用exists实现(and 的优先级要高于or,所以一定要将or的相关操作用()括起来,提高优先级)
select *
from emp e
where exists (select deptno
from dept d
where (d.deptno = 10 or d.deptno = 20)
and e.deptno = d.deptno)
模糊查询:like _ ,%,escape ‘\‘ _% escape ‘\’
在like的语句中,需要使用占位符或者通配符
使用like的时候要慎重,因为like的效率比较低
使用like可以参考使用索引,但是要求不能以%开头
查询名字以S开头的用户
select * from emp where ename like('S%')
查询名字以S开头且倒数第二个字符为T的用户
select * from emp where ename like('S%T_');
select * from emp where ename like('S%T%');
查询名字中带%的用户
select * from emp where ename like('%\%%') escape('\')
select * from emp order by sal;
select * from emp order by sal desc;
select * from emp order by ename;
select * from emp order by sal desc,ename asc;
字符串连接符
select 'my name is '||ename name from emp;
select concat('my name is ',ename) from emp;
计算所有员工的年薪(null是比较特殊的存在,null做任何运算都还是为null,因此要将空进行转换)
select ename,(e.sal+e.comm)*12 from emp e;
nvl(arg1,arg2),如果arg1是空,那么返回arg2,如果不是空,则返回原来的值
select ename,(e.sal+nvl(e.comm,0))*12 from emp e;
dual是oracle数据库中的一张虚拟表,没有实际的数据,可以用来做测试
select 100+null from dual;
–A
select * from emp where deptno =30;
–B
select * from emp where sal >1000;
–并集,将两个集合中的所有数据都进行显示,但是不包含重复的数据
select * from emp where deptno =30 union
select * from emp where sal >1000;
–全集,将两个集合的数据全部显示,不会完成去重的操作
select * from emp where deptno =30 union all
select * from emp where sal >1000;
–交集,两个集合中交叉的数据集,只显示一次
select * from emp where deptno =30 intersect
select * from emp where sal >1000;
–差集,包含在A集合而不包含在B集合中的数据,跟A和B的集合顺序相关
select * from emp where deptno =30 minus
select * from emp where sal >1000;
/*
组函数又称为聚合函数
输入多个值,最终只会返回一个值
组函数仅可用于选择列表或查询的having子句
单行函数
输入一个值,输出一个值
*/
–查询所有员工的薪水总和
select sum(sal) from emp;
–查看表中有多少条记录
select deptno,count(*) from emp group by deptno where count(*) >3;
–concat:表示字符串的连接 等同于||
select concat('my name is ', ename) from emp;
–将字符串的首字母大写
select initcap(ename) from emp;
–将字符串全部转换为大写
select upper(ename) from emp;
–将字符串全部转换为小写
select lower(ename) from emp;
–填充字符串
select lpad(ename,10,'*') from emp;
select rpad(ename,10,'*') from emp;
–去除空格
select trim(ename) from emp;
select ltrim(ename) from emp;
select rtrim(ename) from emp;
–查找指定字符串的位置
select instr('ABABCDEF','A') from emp;
–查看字符串的长度
select length(ename) from emp;
–截取字符串的操作
select substr(ename,0,2) from emp;
–替换操作
select replace('ababefg','ab','hehe') from emp;
–给小数进行四舍五入操作,可以指定小数部分的位数
select round(123.123,2) from dual;
select round(123.128,2) from dual;
select round(-123.128,2) from dual;
–截断数据,按照位数去进行截取,但是不会进行四舍五入的操作
select trunc(123.128,2) from dual;
–取模操作
select mod(10,4) from dual;
select mod(-10,4) from dual;
–向上取整
select ceil(12.12) from dual;
–向下取整
select floor(13.99) from dual;
–取绝对值
select abs(-100) from dual;
–获取正负值
select sign(-100) from dual;
–x的y次幂
select power(2,3) from dual;
select sysdate from dual;
select current_date from dual;
–add_months,添加指定的月份
select add_months(hiredate,2),hiredate from emp;
–返回输入日期所在月份的最后一天
select last_day(sysdate) from dual;
–两个日期相间隔的月份
select months_between(sysdate,hiredate) from emp;
–返回四舍五入的第一天
select sysdate 当时日期,
round(sysdate) 最近0点日期,
round(sysdate,'day') 最近星期日,
round(sysdate,'month') 最近月初,
round(sysdate,'q') 最近季初日期,
round(sysdate,'year') 最近年初日期 from dual;
–返回下周的星期几
select next_day(sysdate,'星期一') from dual;
–提取日期中的时间
select
extract(hour from timestamp '2001-2-16 2:38:40 ' ) 小时,
extract(minute from timestamp '2001-2-16 2:38:40 ' ) 分钟,
extract(second from timestamp '2001-2-16 2:38:40 ' ) 秒,
extract(DAY from timestamp '2001-2-16 2:38:40 ' ) 日,
extract(MONTH from timestamp '2001-2-16 2:38:40 ' ) 月,
extract(YEAR from timestamp '2001-2-16 2:38:40 ' ) 年
from dual;
–返回日期的时间戳
select localtimestamp from dual;
select current_date from dual;
select current_timestamp from dual;
–给指定的时间单位增加数值
select
trunc(sysdate)+(interval '1' second), --加1秒(1/24/60/60)
trunc(sysdate)+(interval '1' minute), --加1分钟(1/24/60)
trunc(sysdate)+(interval '1' hour), --加1小时(1/24)
trunc(sysdate)+(INTERVAL '1' DAY), --加1天(1)
trunc(sysdate)+(INTERVAL '1' MONTH), --加1月
trunc(sysdate)+(INTERVAL '1' YEAR), --加1年
trunc(sysdate)+(interval '01:02:03' hour to second), --加指定小时到秒
trunc(sysdate)+(interval '01:02' minute to second), --加指定分钟到秒
trunc(sysdate)+(interval '01:02' hour to minute), --加指定小时到分钟
trunc(sysdate)+(interval '2 01:02' day to minute) --加指定天数到分钟
from dual;
select '999'+10 from dual;
–date :to_char
select to_char(sysdate,'YYYY-MI-SS HH24:MI:SS') from dual;
– number : to_char
select to_char(123.456789,'9999') from dual;
select to_char(123.456789,'0000.00') from dual;
select to_char(123.456789,'$0000.00') from dual;
select to_char(123.456789,'L0000.00') from dual;
select to_char(123456789,'999,999,999,999') from dual;
–to_date:转换之后都是固定的格式
select to_date('2019/10/10 10:10:10','YYYY-MM-DD HH24:MI:SS') from dual;
–to_number:转成数字
select to_number('123,456,789','999,999,999') from dual;
–显示没有上级管理的公司首脑
select ename,nvl(to_char(mgr),'boss') from emp where mgr is null;
–显示员工雇佣期满6个月后下一个星期五的日期
select hiredate,next_day(add_months(hiredate,6),'星期五') from emp;
–decode,case when
–给不同部门的人员涨薪,10部门涨10%,20部门涨20%,30部门涨30%
select ename,sal,deptno,decode(deptno,10,sal*1.1,20,sal*1.2,30,sal*1.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 * 1.3
end from emp;
姓名 | 性别 | 年龄 |
---|---|---|
张三 | 男 | 50 |
创建表 |
create table test(
id number(10) primary key,
type number(10) ,
t_id number(10),
value varchar2(5)
);
insert into test values(100,1,1,'张三');
insert into test values(200,2,1,'男');
insert into test values(300,3,1,'50');
insert into test values(101,1,2,'刘二');
insert into test values(201,2,2,'男');
insert into test values(301,3,2,'30');
insert into test values(102,1,3,'刘三');
insert into test values(202,2,3,'女');
insert into test values(302,3,3,'10');
答案
select decode(type, 1, value) 姓名,
decode(type, 2, value) 性别,
decode(type, 3, value) 年龄
from test;
select min(decode(type, 1, value)) 姓名,
min(decode(type, 2, value)) 性别,
min(decode(type, 3, value)) 年龄
from test group by t_id;
表内容:
2005-05-09 | 胜 |
---|---|
2005-05-09 | 胜 |
2005-05-09 | 负 |
2005-05-09 | 负 |
2005-05-10 | 胜 |
2005-05-10 | 负 |
2005-05-10 | 负 |
如果要生成下列结果, 该如何写sql语句?
胜 | 负 | |
---|---|---|
2005-05-09 | 2 | 2 |
2005-05-10 | 1 | 2 |
创建表 |
create table tmp(rq varchar2(10),shengfu varchar2(5));
insert into tmp values('2005-05-09','胜');
insert into tmp values('2005-05-09','胜');
insert into tmp values('2005-05-09','负');
insert into tmp values('2005-05-09','负');
insert into tmp values('2005-05-10','胜');
insert into tmp values('2005-05-10','负');
insert into tmp values('2005-05-10','负');
答案
select rq,decode(shengfu,'胜',1),decode(shengfu,'负',2) from tmp;
select rq,
count(decode(shengfu, '胜', 1)) 胜,
count(decode(shengfu, '负', 2)) 负
from tmp
group by rq;
姓名 | 语文 | 数学 | 英语 |
---|---|---|---|
王五 | 89 | 56 | 89 |
建表 |
create table STUDENT_SCORE
(
name VARCHAR2(20),
subject VARCHAR2(20),
score NUMBER(4,1)
);
insert into student_score (NAME, SUBJECT, SCORE) values ('张三', '语文', 78.0);
insert into student_score (NAME, SUBJECT, SCORE) values ('张三', '数学', 88.0);
insert into student_score (NAME, SUBJECT, SCORE) values ('张三', '英语', 98.0);
insert into student_score (NAME, SUBJECT, SCORE) values ('李四', '语文', 89.0);
insert into student_score (NAME, SUBJECT, SCORE) values ('李四', '数学', 76.0);
insert into student_score (NAME, SUBJECT, SCORE) values ('李四', '英语', 90.0);
insert into student_score (NAME, SUBJECT, SCORE) values ('王五', '语文', 99.0);
insert into student_score (NAME, SUBJECT, SCORE) values ('王五', '数学', 66.0);
insert into student_score (NAME, SUBJECT, SCORE) values ('王五', '英语', 91.0);
答案(四种方法)
--decode
select ss.name,
max(decode(ss.subject, '语文', ss.score)) 语文,
max(decode(ss.subject, '数学', ss.score)) 数学,
max(decode(ss.subject, '英语', ss.score)) 英语
from student_score ss group by ss.name
--case when
select ss.name,
max(case ss.subject
when '语文' then
ss.score
end) 语文,
max(case ss.subject
when '数学' then
ss.score
end) 数学,
max(case ss.subject
when '英语' then
ss.score
end) 英语
from student_score ss
group by ss.name;
--join
select ss.name,ss.score from student_score ss where ss.subject='语文';
select ss.name,ss.score from student_score ss where ss.subject='数学';
select ss.name,ss.score from student_score ss where ss.subject='英语';
select ss01.name, ss01.score 语文, ss02.score 数学, ss03.score 英语
from (select ss.name, ss.score
from student_score ss
where ss.subject = '语文') ss01
join (select ss.name, ss.score
from student_score ss
where ss.subject = '数学') ss02
on ss01.name = ss02.name
join (select ss.name, ss.score
from student_score ss
where ss.subject = '英语') ss03
on ss01.name = ss03.name;
--union all
select t.name,sum(t.语文),sum(t.数学),sum(t.英语) from (select ss01.name,ss01.score 语文,0 数学,0 英语 from student_score ss01 where ss01.subject='语文' union all
select ss02.name,0 语文,ss02.score 数学,0 英语 from student_score ss02 where ss02.subject='数学' union all
select ss03.name,0 语文,0 数学,ss03.score 英语 from student_score ss03 where ss03.subject='英语') t group by t.name
组函数,一般情况下,组函数都要和group by组合使用
组函数一般用于选择列表或者having条件判断
常用的组函数有5个
select avg(sal) from emp;
select min(sal) from emp;
select max(sal) from emp;
select count(sal) from emp;
select sum(sal) from emp;
group by
–group by,按照某些相同的值去进行分组操作
–group进行分组操作的时候,可以指定一个列或者多个列,但是当使用了groupby 之后,
–选择列表中只能包含组函数的值或者group by 的普通字段
–求每个部门的平均薪水
select avg(sal) from emp group by deptno;
–求平均新书大于2000的部门
select avg(sal),deptno from emp where sal is not null group by deptno having avg(sal) >2000 order by avg(sal);
select count(10000) from emp;
–部门下雇员的工资>2000 人数
select deptno,count(1) from emp where sal>2000 group by deptno
–部门薪水最高
select deptno,max(sal) from emp group by deptno;
–部门里面 工龄最小和最大的人找出来,知道姓名
select deptno,min(hiredate),max(hiredate) from emp group by deptno;
select ename, deptno
from emp e
where hiredate in (select min(hiredate) from emp group by deptno)
or hiredate in (select max(hiredate) from emp group by deptno)
select * from emp
select mm2.deptno, e1.ename, e1.hiredate
from emp e1,
(select min(e.hiredate) mind, max(e.hiredate) maxd, e.deptno
from emp e
group by e.deptno) mm2
where (e1.hiredate = mm2.mind
or e1.hiredate = mm2.maxd)
and e1.deptno = mm2.deptno;
–查询雇员的名称和部门的名称
select ename,dname from emp,dept where emp.deptno = dept.deptno;
–查询雇员名称以及自己的薪水等级
select e.ename,e.sal,sg.grade from emp e,salgrade sg where e.sal between sg.losal and sg.hisal;
–外连接
–需要将雇员表中的所有数据都进行显示,利用等值连接的话只会把关联到的数据显示,
–没有关联到的数据不会显示,此时需要外连接
–分类:左外连接(把左表的全部数据显示)和右外连接(把右表的全部数据显示)
select * from emp e,dept d where e.deptno = d.deptno;--等值连接
select * from emp e,dept d where e.deptno = d.deptno(+);--左外连接
select * from emp e,dept d where e.deptno(+) = d.deptno;--右外连接
–自连接,将一张表当成不同的表来看待,自己关联自己
–将雇员和他经理的名称查出来
select e.ename,m.ename from emp e,emp m where e.mgr = m.empno;
–笛卡尔积,当关联多张表,但是不指定连接条件的时候,会进行笛卡尔积,
–关联后的总记录条数为M*n,一般不要使用
select * from emp e,dept d;
92的表连接语法存在的问题
/*
CROSS JOIN
NATURAL JOIN
USING子句
ON子句
LEFT OUTER JOIN
RIGHT OUTER JOIN
FULL OUTER JOIN
Inner join
*/
–cross join 等同于92语法中的笛卡儿积
select * from emp cross join dept;
–natural join 相当于是等值连接,但是注意,不需要写连接条件,会从两张表中找到相同的列做连接
–当两张表中不具有相同的列名的时候,会进行笛卡儿积操作,自然连接跟92语法的自连接没有任何关系
select * from emp e natural join dept d ;
select * from emp e natural join salgrade sg;
–on子句,可以添加任意的连接条件,
–添加连接条件 相当于92语法中的等值连接
select * from emp e join dept d on e.deptno = d.deptno;
–相当于92语法中的非等值连接,
select * from emp e join salgrade sg on e.sal between sg.losal and sg.hisal;
–left outer join ,会把左表中的全部数据正常显示,右表没有对应的数据直接显示空即可
select * from emp e left outer join dept d on e.deptno = d.deptno;
select * from emp e,dept d where e.deptno = d.deptno(+);
–right outer join ,会把右表中的全部数据正常显示,左表中没有对应的记录的话显示空即可
select * from emp e right outer join dept d on e.deptno = d.deptno;
select * from emp e,dept d where e.deptno(+) = d.deptno;
–full outer join ,相当于左外连接和右外连接的合集
select * from emp e full outer join dept d on e.deptno = d.deptno;
–inner outer join,两张表的连接查询,只会查询出有匹配记录的数据
select * from emp e inner join dept d on e.deptno = d.deptno;
select * from emp e join dept d on e.deptno = d.deptno;
–using,除了可以使用on表示连接条件之外,也可以使用using作为连接条件,此时连接条件的列不再归属于任何一张表
select deptno from emp e join dept d using(deptno);
select e.deptno,d.deptno from emp e join dept d on e.deptno = d.deptno;
–检索雇员名字、所在单位、薪水等级
select e.ename, d.loc, sg.grade
from emp e
join dept d
on e.deptno = d.deptno
join salgrade sg
on e.sal between sg.losal and sg.hisal;
–有哪些人的薪水是在整个雇员的平均薪水之上的
–1、先求平均薪水
select avg(e.sal) from emp e;
–2、把所有人的薪水与平均薪水比较
select * from emp e where e.sal > (select avg(e.sal) from emp e);
–我们要查在雇员中有哪些人是经理人
–1、查询所有的经理人编号
select distinct e.mgr from emp e;
–2、再雇员表中过滤这些编号即可
select * from emp e where e.empno in (select distinct e.mgr from emp e);
–每个部门平均薪水的等级
–1、先求出部门的平均薪水
select e.deptno,avg(e.sal) from emp e group by e.deptno;
–2、跟薪水登记表做关联,求出平均薪水的等级
select t.deptno, sg.grade
from salgrade sg
join (select e.deptno, avg(e.sal) vsal from emp e group by e.deptno) t
on t.vsal between sg.losal and sg.hisal;
视图概念
授权视图
sqlplus /nolog
conn sys/lixinjay@oral as sysdba;
grant create view to scott;
创建视图
create view v_emp as select * from emp where deptno = 30;
-- 视图的使用
select * from v_emp;
–向视图中添加数据,执行成功之后,需要提交事务,绿色表示提交事务,让数据生效,红色表示回滚事务,让数据恢复原状态
insert into v_emp(empno,ename) values(1111,'zhangsan');
select * from emp;
–如果定义的视图是非只读视图的话,可以通过视图向表中插入数据,如果是只读视图,则不可以插入数据
create view v_emp2 as select * from emp with read only;
select * from v_emp2;
--只读视图只提供查询的需求,无法进行增删改操作
insert into v_emp2(empno,ename) values(1234, 'lisi');
--删除视图
drop view v_emp2;
--当删除视图中的数据的时候,如果数据来源于多个基表,则此时不能全部进行删除,只能删除一个表中的数据
– 求平均薪水的等级最低的部门,它的部门名称是什么,我们完全使用子查询
--1、求平均薪水
select e.deptno, avg(e.sal) from emp e group by e.deptno;
--2、求平均薪水的等级
select t.deptno,sg.grade gd
from salgrade sg
join (select e.deptno, avg(e.sal) vsal from emp e group by e.deptno) t
on t.vsal between sg.losal and sg.hisal;
--3、求平均薪水的等级最低的部门
select min(t.gd) from (select t.deptno,sg.grade gd
from salgrade sg
join (select e.deptno, avg(e.sal) vsal from emp e group by e.deptno) t
on t.vsal between sg.losal and sg.hisal) t
--4、求平均薪水的等级最低的部门的部门名称
select d.dname, d.deptno
from dept d
join (select t.deptno, sg.grade gd
from salgrade sg
join (select e.deptno, avg(e.sal) vsal from emp e group by e.deptno) t
on t.vsal between sg.losal and sg.hisal) t
on t.deptno = d.deptno
where t.gd =
(select min(t.gd)
from (select t.deptno, sg.grade gd
from salgrade sg
join (select e.deptno, avg(e.sal) vsal
from emp e
group by e.deptno) t
on t.vsal between sg.losal and sg.hisal) t);
–查看sql语句能够发现,sql中有很多的重复的sql子查询,可以通过视图将重复的语句给抽象出来
–创建视图
create view v_deptno_grade as select t.deptno, sg.grade gd
from salgrade sg
join (select e.deptno, avg(e.sal) vsal from emp e group by e.deptno) t
on t.vsal between sg.losal and sg.hisal;
select d.dname, d.deptno
from dept d
join v_deptno_grade t
on t.deptno = d.deptno
where t.gd =
(select min(t.gd)
from v_deptno_grade t);
conn sys/lixinjay@oral as sysdba;
revoke create view from scott;
管理用户
create user lili identified by 123;
select username from dba_users;
grant create session to lili;
-- 收回授予用户lili用户emp表的权限
revoke all on scott emp from lili
–在oracle中如果需要完成一个列的自增操作,必须要使用序列
/*
create sequence seq_name
increment by n 每次增长几
start with n 从哪个值开始增长
maxvalue n|nomaxvalue 10^27 or -1 最大值
minvalue n|no minvalue 最小值
cycle|nocycle 是否有循环
cache n|nocache 是否有缓存
*/
create sequence my_sequence
increment by 2
start with 1
select my_sequence.currval from dual;
select my_sequence.nextval from dual;
insert into emp(empno,ename) values(my_sequence.nextval,'hehe');
select * from emp;
drop sequence my_sequence
插入操作:
元组值的插入
未指定列,需要给所有列插入值
insert into emp values(2222,'haha','clerk',7902,to_date('2019-11-2','YYYY-MM-dd'),1000,500,10);
向指定列中插入数据,但是插入的列要遵循创建表的规范
insert into emp(empno,ename) values(3333,'wangwu')
–创建表的其他方式
–复制表同时复制表数据,不会复制约束
create table emp2 as select * from emp;
–复制表结构但是不复制表数据,不会复制约束
create table emp3 as select * from emp where 1=2;
/*
删除操作:
delete from tablename where condition
*/
delete from emp2 where deptno = 10;
delete from emp2;
truncate table emp2;
/*
修改操作:
update tablename set col = val1,col2 = val2 where condition;
可以更新或者修改满足条件的一个列或者多个列
*/
update emp set ename = 'heihei' where ename = 'hehe';
update emp set job='teacher',mgr=7902 where empno = 15;
增删改是数据库的常用操作,在进行操作的时候都需要《事务》的保证, 也就是说每次在pl/sql中执行sql语句之后都需要完成commit的操作
事务变得非常关键:
最主要的目的是为了数据一致性
如果同一份数据,在同一个时刻只能有一个人访问,就不会出现数据错乱的问题,但是在现在的项目中,更多的是并发访问
并发访问的同时带来的就是数据的不安全,也就是不一致
如果要保证数据的安全,最主要的方式就是加锁的方式,MVCC
事务的延申:
最基本的数据库事务
声明式事务
分布式事务
为了提高效率,有可能多个操作会在同一个事务中执行,那么就有可能部分成功,部门失败,基于这样的情况就需要事务的控制。
select * from emp where id = 7902 for update
select * from emp where id = 7902 lock in share mode.
如果不保证事务的话,会造成脏读,不可重复读,幻读。
insert into emp(empno,ename) values(2222,'zhangsan');
commit; -- 提交
delete from emp where empno = 1111;
delete from emp where empno = 2222;
savepoint sp1;
delete from emp where empno = 1234;
rollback to sp1;
commit;
四个特性中,哪个是最关键的?
锁的机制:
为了解决在并发访问的时候,数据不一致的问题,需要给数据加锁 加锁的同时需要考虑《粒度》的问题:
操作的对象:数据库,表,行
一般情况下,锁的粒度越小,效率越高,粒度越大,效率越低
在实际的工作环境中,大部分的操作都是行级锁
1、打开两个mysql的命令行,将自动提交事务给关闭
--查看是否是自动提交 1表示开启,0表示关闭
select @@autocommit;
--设置关闭
set autocommit = 0;
2、数据准备
--创建数据库
create database tran;
--切换数据库 两个窗口都执行
use tran;
--准备数据
create table psn(id int primary key,name varchar(10)) engine=innodb;
--插入数据
insert into psn values(1,'zhangsan');
insert into psn values(2,'lisi');
insert into psn values(3,'wangwu');
commit;
3、测试事务
--事务包含四个隔离级别:从上往下,隔离级别越来越高,意味着数据越来越安全
read uncommitted; --读未提交
read commited; --读已提交
repeatable read; --可重复读
(seariable) --序列化执行,串行执行
--产生数据不一致的情况:
脏读
不可重复读
幻读
隔离级别 | 异常情况 | 异常情况 | |
---|---|---|---|
读未提交 | 脏读 | 不可重复读 | 幻读 |
读已提交 | 不可重复读 | 幻读 | |
可重复读 | 幻读 | ||
序列化 |
4、测试1:脏读 read uncommitted
set session transaction isolation level read uncommitted;
A:start transaction;
A:select * from psn;
B:start transaction;
B:select * from psn;
A:update psn set name='msb';
A:selecet * from psn
B:select * from psn; --读取的结果msb。产生脏读,因为A事务并没有commit,读取到了不存在的数据
A:commit;
B:select * from psn; --读取的数据是msb,因为A事务已经commit,数据永久的被修改
5、测试2:当使用read committed的时候,就不会出现脏读的情况了,当时会出现不可重复读的问题
set session transaction isolation level read committed;
A:start transaction;
A:select * from psn;
B:start transaction;
B:select * from psn;
--执行到此处的时候发现,两个窗口读取的数据是一致的
A:update psn set name ='zhangsan' where id = 1;
A:select * from psn;
B:select * from psn;
--执行到此处发现两个窗口读取的数据不一致,B窗口中读取不到更新的数据
A:commit;
A:select * from psn;--读取到更新的数据
B:select * from psn;--也读取到更新的数据
--发现同一个事务中多次读取数据出现不一致的情况
6、测试3:当使用repeatable read的时候(按照上面的步骤操作),就不会出现不可重复读的问题,但是会出现幻读的问题
set session transaction isolation level repeatable read;
A:start transaction;
A:select * from psn;
B:start transaction;
B:select * from psn;
--此时两个窗口读取的数据是一致的
A:insert into psn values(4,'sisi');
A:commit;
A:select * from psn;--读取到添加的数据
B:select * from psn;--读取不到添加的数据
B:insert into psn values(4,'sisi');--报错,无法插入数据
--此时发现读取不到数据,但是在插入的时候不允许插入,出现了幻读,设置更高级别的隔离级别即可解决
总结:
现在学习的是数据库级别的事务,需要掌握的就是事务的隔离级别和产生的数据不一致的情况
后续会学习声明式事务及事务的传播特性以及分布式事务
/*
语法:
CREATE TABLE [schema.]table
(column datatype [DEFAULT expr] , …
);
*/
create table student
(
-- 一般要给定长度,如果不给默认255,太大占用空间
stu_id number(10),
name varchar2(20),
age number(3),
hiredate date,
grade varchar2(10) default 1,
classes varchar2(10),
email varchar2(50)
);
-- 两种插入方法,元组插入,查询结果的插入
insert into student values(20191109,'zhangsan',22,to_date('2019-11-09','YYYY-MM-DD'),'2','1','[email protected]');
insert into student(stu_id,name,age,hiredate,classes,email) values(20191109,'zhangsan',22,to_date('2019-11-09','YYYY-MM-DD'),'1','[email protected]');
select * from student;
alter table student add address varchar2(100);
alter table student drop column address;
alter table student modify(email varchar2(100));
rename student to stu;
/*
在删除表的时候,经常会遇到多个表关联的情况,多个表关联的时候不能随意删除,需要使用级联删除
cascade:如果有A,B两个表,A中的某一个字段跟B表中的某一个字段做关联,那么再删除表A的时候,需要先将表B删除
set null:再删除的时候,把表的关联字段设置成空
*/
drop table stu;
insert into emp(empno,ename,deptno) values(9999,'hehe',50);
create table student
(
stu_id number(10) primary key,
name varchar2(20) not null,
age number(3) check(age>0 and age<126),
hiredate date,
grade varchar2(10) default 1,
classes varchar2(10),
email varchar2(50) unique,
deptno number(2)
);
insert into student(stu_id,name,age,hiredate,classes,email,deptno) values(20191109,'zhansgan',111,to_date('2019-11-09','YYYY-MM-DD'),'1','[email protected]',10);
alter table student add constraint fk_0001 foreign key(deptno) references dept(deptno);
create index i_ename on emp(ename);
drop index i_ename;
select * from emp where ename = 'SMITH';
解决的问题:数据冗余
第一范式:列不可再分,比如城市
第二范式:确保表中的每列都和主键相关
第三范式:在第二范式的基础上,不能出现传递依赖,表里的列不能出现其他表的非主键字段
select * from emp e where e.deptno = 10;
select ename, deptno, (e.sal + nvl(e.comm, 0)) * 12 n_sal
from emp e
where (e.sal + nvl(e.comm, 0)) * 12 > 30000;
select e.ename, e.sal from emp e where e.comm is null;
select e.ename from emp e where e.sal > 1500 and e.comm is not null;
select e.ename from emp e where e.sal > 1500 or e.comm is not null;
select e.ename,e.sal from emp e where e.ename like('%S%');
select e.ename,e.sal from emp e where e.ename like('JO%');
select ename from emp where ename like ('%\%%') escape('\');
select e.ename, e.sal, e.deptno
from emp e, dept d
where d.dname = 'SALES'
or d.dname = 'RESEARCH';
select e.ename, e.sal, e.deptno
from emp e
where exists (select d.dname
from dept d
where (d.dname = 'SALES' or d.dname = 'RESEARCH')
and e.deptno = d.deptno);
select dname from dept;
select e.ename,(e.sal + nvl(e.comm,0)) * 12 年收入 from emp e;
select e.deptno from emp e where e.ename is null;
select e.ename, e.sal from emp e where e.sal > 2850;
select e.ename, e.sal from emp e where e.sal between 1500 and 2850;
select e.ename, e.deptno from emp e where e.empno = 7566;
select e.ename, e.sal from emp e where e.deptno in (10,30) and e.sal > 1500;
select e.ename, e.sal from emp e where e.ename like('_A%');
select e.ename, e.comm from emp e where e.comm is not null;
select * from emp;
select e.ename, e.sal, e.hiredate from emp e order by e.ename;
select e.ename, e.job, e.hiredate
from emp e
where e.hiredate between To_DATE('1981-2-1', 'YYYY-MM-DD') and
To_DATE('1981-5-1', 'YYYY-MM-DD')
order by e.hiredate;
select e.ename, e.sal, e.comm from emp e order by e.sal, e.comm desc;
select * from emp e where to_char(e.hiredate,'yyyy-mm-dd') like '__82%';
select ename from emp where to_char(hiredate,'yy')='82';
select e.*, (months_between(sysdate, e.hiredate) / 12)
from emp e
where months_between(sysdate, e.hiredate) / 12 between 41 and 42;
select next_day(add_months(e.hiredate,6),'星期一') from emp e;
select ename,nvl(to_char(mgr),'boss') from emp;
select e.*,
(case e.deptno
when 10 then
e.sal * 1.1
when 20 then
e.sal * 1.15
when 30 then
e.sal * 1.2
else
e.sal * 1.18
end)
from emp e;
查询10号部门中编号最新入职的员工,工龄最长的员工的个人信息。
从software‛找到‘f’的位置,用‘*’左戒右填充到15位,去除其中的‘a’。
查询员工的奖金,如果奖金丌为NULL显示‘有奖金’,为null则显示无奖金
写一个查询显示当前日期,列标题显示为Date。再显示六个月后的日期,下一个星期 日的日期,该月最后一天的日期。
查询EMP表按管理者编号升序排列,如果管理者编号为空则把为空的在最前显示
求部门平均薪水
按部门求出工资大亍1300人员的 部门编号、平均工资、最小佣金、最大佣金,幵且最大佣金大亍100
找出每个部门的平均、最小、最大薪水
查询出雇员名,雇员所在部门名称, 工资等级。
–1、求平均薪水最高的部门的部门编号
–求部门的平均薪水
select e.deptno,avg(e.sal) from emp e group by e.deptno;
–求平均薪水最高的部门
select max(t.vsal) from (select e.deptno,avg(e.sal) vsal from emp e group by e.deptno) t
–求部门编号
select t.deptno
from (select e.deptno, avg(e.sal) vsal from emp e group by e.deptno) t
where t.vsal =
(select max(t.vsal)
from (select e.deptno, avg(e.sal) vsal from emp e group by e.deptno) t);
– 2、求部门平均薪水的等级
-- 先求出部门的平均薪水
select deptno,avg(sal) from emp group by deptno;
-- 跟薪水登记表做关联,求出平均薪水的等级
select sg.grade, t.deptno
from salgrade sg
join (select deptno, avg(sal) vsal from emp group by deptno) t
on t.vsal between sg.losal and sg.hisal;
–3、求部门平均的薪水等级
–求部门每个人的薪水等级
select e.deptno, sg.grade
from emp e
join salgrade sg
on e.sal between sg.losal and sg.hisal;
–按照部门求平均等级
select t.deptno, avg(t.grade)
from (select e.deptno, sg.grade
from emp e
join salgrade sg
on e.sal between sg.losal and sg.hisal) t
group by t.deptno;
–限制输出,limit,mysql中用来做限制输出的,但是oracle中不是
–再oracle中,如果需要使用限制输出和分页的功能的话,必须要使用rownum,
–但是rownum不能直接使用,需要嵌套使用
–4、求薪水最高的前5名雇员
select *
from (select * from emp e order by e.sal desc) t1
where rownum <= 5
select * from emp e where rownum <=5 order by e.sal desc
–5、求薪水最高的第6到10名雇员
select t1.*,rownum
from (select * from emp e order by e.sal desc) t1
where rownum <= 10
–使用rownum的时候必须要再外层添加嵌套,此时才能将rownum作为其中的一个列,然后再进行限制输出
select *
from (select t1.*, rownum rn
from (select * from emp e order by e.sal desc) t1
where rownum <= 10) t
where t.rn > 5
and t.rn <= 10;