一、创建表及初始化数据
1、表结构说明:
bonus职位表( ename 员工姓名,job 工作,sal 薪水, comm 佣金)
emp员工表(empno员工号/ename员工姓名/job工作/mgr上级编号/hiredate受雇日期/sal薪金/comm佣金/deptno部门编号)
dept部门表(deptno部门编号/dname部门名称/loc地点)
salgrad 薪金级别(grade 初级, losal 中级,hisal 高级)
创建职位表:代码如下
create table BONUS
(
ename VARCHAR2(10),
job VARCHAR2(9),
sal NUMBER,
comm NUMBER
)
创建部门表:
create table DEPT
(
deptno NUMBER(2) not null,
dname VARCHAR2(14),
loc VARCHAR2(13)
);
创建员工表:
create table EMP
(
empno NUMBER(4) not null,
ename VARCHAR2(10),
job VARCHAR2(9),
mgr NUMBER(4),
hiredate DATE,
sal NUMBER(7,2),
comm NUMBER(7,2),
deptno NUMBER(2)
);
创建薪水等级表:
create table SALGRADE
(
grade NUMBER,
losal NUMBER,
hisal NUMBER
)
2:给部门表插入数据
insert into DEPT (deptno, dname, loc)
values (10, 'ACCOUNTING', 'NEW YORK');
insert into DEPT (deptno, dname, loc)
values (20, 'RESEARCH', 'DALLAS');
insert into DEPT (deptno, dname, loc)
values (30, 'SALES', 'CHICAGO');
insert into DEPT (deptno, dname, loc)
values (40, 'OPERATIONS', 'BOSTON');
commit;
给员工表插入数据:
insert into EMP (empno, ename, job, mgr, hiredate, sal, comm, deptno)
values (7369, 'SMITH', 'CLERK', 7902, to_date('17-12-1980', 'dd-mm-yyyy'), 800, null, 20);
insert into EMP (empno, ename, job, mgr, hiredate, sal, comm, deptno)
values (7499, 'ALLEN', 'SALESMAN', 7698, to_date('20-02-1981', 'dd-mm-yyyy'), 1600, 300, 30);
insert into EMP (empno, ename, job, mgr, hiredate, sal, comm, deptno)
values (7521, 'WARD', 'SALESMAN', 7698, to_date('22-02-1981', 'dd-mm-yyyy'), 1250, 500, 30);
insert into EMP (empno, ename, job, mgr, hiredate, sal, comm, deptno)
values (7566, 'JONES', 'MANAGER', 7839, to_date('02-04-1981', 'dd-mm-yyyy'), 2975, null, 20);
insert into EMP (empno, ename, job, mgr, hiredate, sal, comm, deptno)
values (7654, 'MARTIN', 'SALESMAN', 7698, to_date('28-09-1981', 'dd-mm-yyyy'), 1250, 1400, 30);
insert into EMP (empno, ename, job, mgr, hiredate, sal, comm, deptno)
values (7698, 'BLAKE', 'MANAGER', 7839, to_date('01-05-1981', 'dd-mm-yyyy'), 2850, null, 30);
insert into EMP (empno, ename, job, mgr, hiredate, sal, comm, deptno)
values (7782, 'CLARK', 'MANAGER', 7839, to_date('09-06-1981', 'dd-mm-yyyy'), 2450, null, 10);
insert into EMP (empno, ename, job, mgr, hiredate, sal, comm, deptno)
values (7788, 'SCOTT', 'ANALYST', 7566, to_date('19-04-1987', 'dd-mm-yyyy'), 3000, null, 20);
insert into EMP (empno, ename, job, mgr, hiredate, sal, comm, deptno)
values (7839, 'KING', 'PRESIDENT', null, to_date('17-11-1981', 'dd-mm-yyyy'), 5000, null, 10);
insert into EMP (empno, ename, job, mgr, hiredate, sal, comm, deptno)
values (7844, 'TURNER', 'SALESMAN', 7698, to_date('08-09-1981', 'dd-mm-yyyy'), 1500, 0, 30);
insert into EMP (empno, ename, job, mgr, hiredate, sal, comm, deptno)
values (7876, 'ADAMS', 'CLERK', 7788, to_date('23-05-1987', 'dd-mm-yyyy'), 1100, null, 20);
insert into EMP (empno, ename, job, mgr, hiredate, sal, comm, deptno)
values (7900, 'JAMES', 'CLERK', 7698, to_date('03-12-1981', 'dd-mm-yyyy'), 950, null, 30);
insert into EMP (empno, ename, job, mgr, hiredate, sal, comm, deptno)
values (7902, 'FORD', 'ANALYST', 7566, to_date('03-12-1981', 'dd-mm-yyyy'), 3000, null, 20);
insert into EMP (empno, ename, job, mgr, hiredate, sal, comm, deptno)
values (7934, 'MILLER', 'CLERK', 7782, to_date('23-01-1982', 'dd-mm-yyyy'), 1300, null, 10);
commit;
给薪水等级表插入数据:
insert into SALGRADE (grade, losal, hisal)
values (1, 700, 1200);
insert into SALGRADE (grade, losal, hisal)
values (2, 1201, 1400);
insert into SALGRADE (grade, losal, hisal)
values (3, 1401, 2000);
insert into SALGRADE (grade, losal, hisal)
values (4, 2001, 3000);
insert into SALGRADE (grade, losal, hisal)
values (5, 3001, 9999);
commit;
别名练习
–别名
–列的别名
SELECT ename AS姓名, job AS工作FROM emp;--省略了双引号
SELECT ename AS "姓名", job AS "工作" FROM emp;--最标准的写法,在别名有空格的时候不能省略双引号
SELECT ename "姓名", job "工作" FROM emp; --省略了as
SELECT ename 姓名, job 工作FROM emp;--省略as和双引号
--表的别名
SELECT * FROM emp t;--给表起别名不能加as;
SELECT t.ename,t.job FROM emp t ;-- 表的别名引用字段
SELECT empQWERTYUIO.ename,empQWERTYUIO.job FROM empQWERTYUIO ;--使用表名去引用字段相对麻烦
SELECT emp.ename,emp.job FROM emp t ;--一旦给表起了别名, 那么就只能使用别名去引用字段,原本的表名不可用
字符和日期:
--需求1:查询关于KING这个人的记录。
SELECT * FROM emp WHERE ename='king';--错误
SELECT * FROM emp WHERE ename='KING';--正确,具体数据库的值是区分大小写。
--需求2:查询入职日期是1987/4/19的员工的信息
SELECT * FROM emp WHERE hiredate ='1987/4/19';--数据库默认是日期的格式不对。导致无法将字符串隐式转换为日期
SELECT * FROM emp WHERE hiredate ='17-12月-80';--数据库默认的日期格式,字符串可以隐式转换为日期
--1987/4/19格式是工具给你转的
通配符练习
--需求1:查询名称是带有”x”字符的员工的记录信息。
SELECT * FROM emp WHERE ename LIKE'%x%';
--需求2:查询员工名称中含有下划线(“_”)的员工.
SELECT * FROM emp WHERE ename LIKE'%_%'; --为什么全查出来:sql的通配符%(任意多个字符) _(任意一个)
SELECT * FROM emp WHERE ename LIKE'%\_%'ESCAPE'\';--用ESCAPE来声明一个转义字符,语句中,该转义字符之后的字符,都作为普通字符来处理。
SELECT * FROM emp WHERE ename LIKE'%|_%'ESCAPE'|';
--需求3:查询姓名是4个字符的员工的信息。
SELECT * FROM emp WHERE ename LIKE'____';
in和not in过滤时的空值问题
--需求1:查询10号部门和20号部门的员工;
SELECT * FROM emp WHERE deptno IN(10,20);
--需求2:查询10号和20号以及没有部门的员工部门的员工;
SELECT * FROM emp WHERE deptno IN(10,20,NULL);--失败
--分析:首先要明白in的原理是什么?
--解决方法:
SELECT * FROM emp WHERE deptno IN(10,20) OR deptno ISnull;
--deptno = 10 OR deptno = 20 OR deptno IS NULL --或的关系只要有一个结果的true 返回的就是true
--需求3:查询不是10号和20号以及没有部门的员工部门的员工;
SELECT * FROM emp WHERE deptno NOTIN(10,20,NULL);--失败
--deptno!=10 AND deptno!= 20 AND deptno IS NOT NULL --与的关系 ,只要有一个不满足返回就是false
SELECT * FROM emp WHERE deptno NOTIN(10,20) AND deptno ISNOTnull;
排序查询
--需求:查询所有员工信息,要求按照部门和员工号的倒序排序,
SELECT * FROM emp ORDERBY deptno,empno DESC;--desc关键字,只能对最靠近的一个字段起作用
SELECT * FROM emp ORDERBY deptno desc,empno DESC;
日期函数:
--需求1:计算员工的工龄(工龄:当前的日期和入职的日期的差),要求分别显示员工入职的天数、多少月、多少年。
SELECT ename, SYSDATE-hiredate 工龄天,
(SYSDATE-hiredate)/30工龄月不精确,months_between(SYSDATE,hiredate) 工龄月精确,
TRUNC (months_between(SYSDATE,hiredate)/12) 工龄年精确
FROM emp;
--需求2:查看当月最后一天的日期。
SELECT last_day(SYSDATE) FROM dual;
--需求3:查看指定日期的下一个星期天或星期一的日期。(next_day(基础日期,星期几))--星期日是1,星期一2
SELECT next_day(SYSDATE,1) FROM dual;
SELECT next_day(SYSDATE,2) FROM dual;
转换函数:
--需求:查询10号部门的信息,分别使用数字和字符串作为条件的值。
SELECT * FROM emp WHERE deptno=10;
SELECT * FROM emp WHERE deptno='10';--字符串隐式转换为数字了
SELECT * FROM emp WHERE deptno='10q';--隐式转换的前提,是能转换才可以。
日期查询:
--需求1:显示今天的完整日期,结果参考:“2015-07-06 11:07:25”。
SELECT to_char(SYSDATE,'yyyy-MM-dd HH:mm:ss') FROM dual;--java的日期格式,和sql的不一样
SELECT to_char(SYSDATE,'yyyy-mm-dd hh24:mi:ss') FROM dual;--sql--24小时制
SELECT to_char(SYSDATE,'yyyy-mm-dd hh:mi:ss') FROM dual;--sql--12小时制
SELECT to_char(SYSDATE,'yyYy-Mm-Dd hH24:mi:ss') FROM dual;--格式不区分大小写
--需求2:显示今天是几号,不包含年月和时间,结果参考:“8日”。
SELECT to_char(SYSDATE,'dd')||'日'FROM dual;--字符串拼接方式
SELECT to_char(SYSDATE,'dd"日"') FROM dual;--格式中直接加入固定值
--需求3:显示当月最后一天是几号,结果参考:”30“。
SELECT to_char(last_day(SYSDATE),'dd') FROM dual;
--需求4:xiaoming的入职日期是2015-03-15,由于其入职日期当时忘记录入,现在请将其插入到emp表中。
UPDATE emp SET hiredate =to_date('2015-03-15','yyyy-mm-dd') WHERE ename ='xiao_ming';
COMMIT;
--需求5:查看2015年2月份最后一天是几号,结果参考“28“
SELECT last_day(to_date('201502','yyyymm')) FROM dual;
SELECT to_date('201502','yyyymm') FROM dual;--日期的默认值,不指定日期,默认1号
2016-07-20:
--需求1:显示今天的完整日期,结果参考:“2015-07-06 11:07:25”。
SELECT to_char(SYSDATE,'yyYy-mm-dD HH24:mi:ss') FROM dual;
--oracle的日期格式和java不一样
--需求2:显示今天是几号,不包含年月和时间,结果参考:“8日”。
SELECT to_char(SYSDATE,'dd')||'日'FROM dual;
--需求3:显示当月最后一天是几号,结果参考:”30“。
SELECT to_char(last_day(SYSDATE),'dd') FROM dual;
--需求4:xiaoming的入职日期是2015-03-15,由于其入职日期当时忘记录入,现在请将其插入到emp表中。
UPDATE emp SET hiredate = to_date('2015-03-15','yyyy-mm-dd') WHERE ename = 'xiao_ming';
SELECT * FROM emp;
COMMIT;
--需求5:查看2015年2月份最后一天是几号,结果参考“28“
SELECT to_char(last_day(to_date('2015-02','yyyy-mm')),'dd') FROM dual;
-- 不指定具体日期的话, 默认从1开始
需求:查看显示今天是星期几
SELECT to_char(SYSDATE,'day') FROM dual;
滤空函数(通用函数)
--需求:查询员工的月收入(基本薪资+奖金)
SELECT ename,sal+nvl(comm,0) 月收入FROM emp;
SELECT ename ,NVL2(sal,sal,0)+nvl(comm,0) FROM emp;--为了小明
SELECTcoalesce(NULL,NULL,1,2) FROM dual;--返回第一个不为空的值
多行函数
多行函数的概念
多行函数也称之为分组函数、聚集函数。
简答的说就是把多行的值汇聚计算成一个值。
常见的分组函数:
count (次数)、max(最大值)、min(最小值)、sum、avg(平均数)
空值问题
多行函数会自动滤空。
需求:统计计算员工的平均奖金。(不同需求不同结果)
--需求:统计计算员工的平均奖金。(不同需求不同结果)
SELECTAVG(comm) FROM emp;--统计的是有奖金的人的平均奖金
--相当于
SELECTSUM(comm)/COUNT(comm) FROM emp;--多行函数会自动滤空
--统计所有人的平均奖金
SELECTAVG(nvl(comm,0)) FROM emp;
分组group by
--需求1:查询显示各个部门的平均薪资情况,并且按照部门号从低到高排列。
SELECT deptno, AVG(sal) FROM emp GROUPBY deptno ORDERBY deptno;
--需求2:查询显示各个部门的不同工种的平均薪资情况,并且按照部门号从低到高排列
SELECT deptno,job, AVG(sal) FROM emp GROUPBY deptno,job ORDERBY deptno;
.过滤分组(havi
--需求:查询平均工资大于2000的部门信息,要求显示部门号和平均工资
SELECT deptno, AVG(sal) FROM emp WHEREavg(sal)>2000GROUPBY deptno;
-- 只要条件中有分组函数的一律使用 having
SELECT deptno, AVG(sal) FROM emp GROUPBY deptno HAVINGavg(sal)>2000;
多表连接的类型
根据连接方式的不同,Oracle的多表关联的类型分为:
内连接、外连接、自连接。
内连接分为:等值内连接、不等值内连接
外连接分为:左外连接、右外连接、全外连接
自连接是一种特殊的关联,可以包含内连接和外连接的连接方式。
6.6.1.等值内连接
等值内连接也称之为等值连接。
【示例】
----需求:查询一下员工信息,并且显示其部门名称
SELECT * FROM emp t1,dept t2 WHERE t1.deptno =t2.deptno;--隐式内连接(mysql和oradcle都支持)
SELECT * FROM emp t1 INNERJOIN dept t2 ON t1.deptno=t2.deptno;--显现内连接(sql99)
6.6.2.不等值内连接
不等值内连接也称之为不等值连接。
【示例】需求:查询员工信息,要求显示员工的编号、姓名、月薪、工资级别。
--分析:要完成这个需求,需要使用到下面两张表:
--【示例】需求:查询员工信息,要求显示员工的编号、姓名、月薪、工资级别。
SELECT * FROM emp t1,salgrade t2 WHERE t1.sal BETWEEN t2.losal AND t2.hisal;--不等值连接,连接条件,一个表的字段在另外一个表的两个或多个字段之间
SELECT * FROM emp t1 INNERJOIN salgrade t2 ON t1.sal BETWEEN t2.losal AND t2.hisal;--sql99
6.7.外连接
分为左外连接,右外连接,全外连接。
6.7.1.左外连接
--查询"所有"员工信息,要求显示员工号,姓名 ,和部门名称--要求使用左外连接
--查询"所有"员工信息,要求显示员工号,姓名 ,和部门名称--要求使用左外连接
SELECT * FROM emp t1 LEFTOUTERJOIN dept t2 ON t1.deptno=t2.deptno;--sql99标准语法
SELECT * FROM emp t1,dept t2 WHERE t1.deptno=t2.deptno(+);--oracle私有语法(mysql不支持),+放到右边是左外,你可以认为(+)是附加补充的意思。--要求查询所有的信息的表,我们可以称之为主表,而补充信息的表,称之为从表
6.7.2.右外连接
----查询所有部门及其下属的员工的信息。--右外连接
SELECT * FROM emp t1 RIGHTOUTERJOIN dept t2 ON t1.deptno=t2.deptno;--sql99--右外连接--右边表(dept)数据全部显示。
SELECT * FROM emp t1,dept t2 WHEREt1.deptno(+)=t2.deptno;--oracle语法,右外连接
6.7.3.如何选择左外和右外
SELECT t1.*,t2.* FROM dept t1 ,emp t2 WHERE t1.deptno=t2.deptno(+);
--1.到底是使用左外还是右外,主要是看两张表的在语句中的位置,
--两张表是有主从关系,一般把主表放在左边,----一般两张表的情况下,我们都使用左连接.
--2.+到底是放在条件哪边?左外连接的+放在右边,右外连接的+放在左边.----记忆的方法:(+)放在从表的一方,起到数据附加的作用.
简单的说:左外连接就是左边的表的数据全部显示,右外就是右边的表的数据全部显示。
6.7.4.全外连接
左表和右表的数据全部都显示,而且不是笛卡尔集。
相当于左外+右外的数据。
【示例】
需求:要求将所有员工和所有部门都显示出来
–全外连接
SELECT * FROM emp t1 LEFTOUTERJOIN dept t2 on t1.deptno=t2.deptno
UNION
SELECT * FROM emp t1 RIGHTJOIN dept t2 ON t1.deptno=t2.deptno;
SELECT * FROM emp t1 FULLOUTERJOIN dept t2 ON t1.deptno=t2.deptno;–sql99语法,Oracle没有支持的语法。而且,mysql没有全外
子查询:
--子查询
--分析一下:谁的工资比scott高?--->1,scott工资是多少2,谁的工资比3000高
SELECT sal FROM emp WHERE ename='SCOTT';
SELECT * FROM emp WHERE sal >3000;
SELECT * FROM emp WHERE sal >(SELECT sal FROM emp WHERE ename='SCOTT');
--需求:查找工作和'Rose' 这个人的工作一样的员工信息
SELECT job FROM emp WHERE ename = 'Rose';
SELECT * FROM emp WHERE job =(SELECT job FROM emp WHERE ename = 'Rose');
SELECT * FROM emp;
--需求:查找工作和'Rose' 这个人的工作不一样的员工信息
SELECT * FROM emp WHERE job !=(SELECT job FROM emp WHERE ename = 'Rose');
--结论: 只要子查询返回的结果是null的话, 那么主查询的结果就一定是null
1.5.2.In操作符
【示例】
需求:查找工作和'SMITH' 'ALLEN' 这两个人的工作一样的员工信息
--需求:查找工作和'SMITH' 'ALLEN' 这两个人的工作不一样的员工信息
--需求:查找工作和'SMITH' 'ALLEN' 这两个人的工作一样的员工信息
SELECT JOB FROM emp WHERE ename IN('SMITH','ALLEN');
SELECT * FROM emp WHERE job IN(SELECT JOB FROM emp WHERE ename IN('SMITH','ALLEN'));
--需求:查找工作和'SMITH' 'ALLEN' 这两个人的工作不一样的员工信息
SELECT * FROM emp WHERE job NOT IN(SELECT JOB FROM emp WHERE ename IN('SMITH','ALLEN'));
1.5.3.Any和all操作符
【示例】需求:查询工资比30号部门任意一个员工的工资高的员工信息。--面试题
【示例】需求:查询工资比30号部门所有员工的工资高的员工信息。
--需求:查询工资比30号部门任意一个员工的工资高的员工信息。--面试题
SELECT * FROM emp WHERE deptno =30;
--任意一个:比最低的那个高就ok。
SELECT * FROM emp WHERE sal >(SELECT MIN(sal) FROM emp WHERE deptno=30);
--any(多行函数)
SELECT * FROM emp WHERE sal >ANY(SELECT sal FROM emp WHERE deptno=30);
--【示例】需求:查询工资比30号部门所有员工的工资高的员工信息。
SELECT * FROM emp WHERE sal>(SELECT MAX (sal) FROM emp WHERE deptno=30);
--all(多个返回记录)--max(sal)
SELECT * FROM emp WHERE sal>ALL(SELECT sal FROM emp WHERE deptno=30);
--需求:根据行号查询出第四条到第六条的员工信息。
SELECT ROWNUM,t.* FROM emp t;
SELECT ROWNUM,t.* FROM emp t WHERE ROWNUM >=4 AND ROWNUM<=6;