一、案例:检查 1997 年入职的员工
Select * from employees where to_char(hire_date,'yyyy') like '1997';
二、单行函数补充
单行函数特点
单行函数会作用于每一行指定的数据,每一行产生一个结果。
三、组函数(聚合函数)
组函数特点
组函数作用于一组数据,一组只产生一个结果。
常用组函数
表格
| 函数 | 说明 |
|---|---|
avg(字段) |
求平均值 |
sum(字段) |
求和 |
max(字段) |
求最大值 |
min(字段) |
求最小值 |
count(字段) |
统计行数 |
案例
1. 查询所有员工平均工资
Select avg(salary) from employees;
2. 查询平均工资、工资总和、最高工资、最低工资
Select avg(salary),sum(salary),max(salary),min(salary) from employees;
3. 统计公司员工数量
--方式1:统计表全部非空行
select count(*) from employees;
--方式2:统计主键,主键非空,推荐
select count(employee_id) from employees;
--方式3:统计该字段非空的行数,null会被自动忽略
select count(commission_pct) from employees;
💡注意:
count(字段)会自动忽略字段为 null 的行 ;统计全表记录优先使用count(*)或count(主键)。
四、分组查询 --- group by
语法
select 字段 ... from 表名 where ... group by 字段 order by...;
group by 后面填写分组条件字段。
案例 1:查询各个部门的平均工资
分组条件:department_id 部门编号
Select avg(salary) from employees group by department_id;
案例 2:查询各个部门、各个职位员工的平均工资
分组条件:department_id,job_id
Select department_id,job_id,avg(salary)
from employees
group by department_id ,job_id;
⚠️ group by 使用三大原则
- 出现在 group by 子句中的字段,才可以直接写在 select 子句中;
- 没有出现在 group by 的字段,必须配合组函数写在 select 中;
- 如果 group by 中字段使用单行函数,select 对应字段也要使用相同单行函数。
案例:查询 1997 年各个月份入职员工总人数
-
where 筛选 1997 年数据
-
按入职月份分组
-
count 统计数量
Select count(*)
From employees
Where to_char(hire_date,'yyyy')='1997'
Group by to_char(hire_date,'mm');
五、Having 条件筛选子句
having:对分组之后的结果做二次筛选。 where:分组之前对原始数据筛选。
完整语法
select 字段 ...from 表名 where ... group by ... having...order by;
案例 1:查询 1997 各个月份入职人数,只展示人数大于 3 的月份
Select count(*)
From employees
Where to_char(hire_date,'yyyy')='1997'
Group by to_char(hire_date,'mm')
Having count(*)>3;
案例 2:查询 50、60、90 号部门各自平均工资
方式① having 实现(不推荐)
Select department_id,avg(salary)
From employees
Group by department_id
Having department_id in(50,60,90);
方式② where 实现(推荐)
Select department_id,avg(salary)
From employees
Where department_id in(50,60,90)
Group by department_id;
💡注意:where 和 having 都能实现的需求,优先使用 where。where 在分组前过滤,减少参与分组的数据量,性能更好。
六、Select 完整语句 & 执行顺序
完整 SQL 模板
Select ... from...where...group by...having...order by...;
执行顺序(非常重要)
- From:确定查询哪一张表
- Where:原始数据初次筛选
- Group by:对筛选后的数据进行分组
- Having:分组完成后,对分组结果再次筛选
- Select:生成目标结果集
- Order by:对最终结果集排序
记忆口诀:查表→筛原始→分组→筛分组结果→输出列→排序
七、Oracle 伪列
伪列:Oracle 系统维护的特殊列,物理表中并不真实存在 ;
select *无法查询,必须手动指定列名。
1. rowid
rowid 是根据数据物理存储地址生成的 18 位唯一字符串。 rowid 定位数据效率极高;一般开发不会手动写,数据库内部自动使用。
select employee_id,first_name,salary,rowid from employees;
2. rownum
rownum:给查询结果集生成自增序列号,永远从 1 开始。
select employee_id,first_name,salary,rownum from employees;
案例:查询前 5 名员工信息
Select employee_id,first_name,salary
From employees where rownum<=5;
⚠️重点限制: rownum 做 where 条件:支持
=1、<、<=、>=1;不能直接写 rownum>1、rownum>=2。
rownum 和 order by 的坑
❌错误写法:先截取,后排序,拿不到工资最高前 5
Select employee_id,first_name,salary
from employees where rownum<=5
order by salary desc;
✅正确写法:子查询先排序,外层再用 rownum 截取
select * from (select * from employees order by salary desc)
where rownum<=5;
💡小知识点:同时查询
*和 rownum,表必须起别名
Select e.*,rownum
From employees e;
八、子查询(嵌套查询)
子查询:select 语句内部再嵌入 select 语句。
①子查询返回:一行一列
需求:查询工资高于平均工资的员工信息
select * from employees where salary>(select avg(salary) from employees);
②子查询返回:多行一列(配合 in)
需求:查询和 Steven 同一个部门的员工信息
select * from employees
where department_id in (select department_id from employees where first_name='Steven');
③子查询返回多行多列(常用于排序后分页、取 topN)
需求:查询工资最高前 5 个人信息
select * from (select * from employees order by salary desc)
where rownum<=5;
九、Oracle 分页查询【重点】
分页:将大批量数据分段展示,依靠
rownum + 子查询实现。
案例 1:查询第 6~10 条员工信息
select * from (select e.*,rownum rn from employees e)
where rn>=6 and rn<=10;
案例 2:查询工资最高的第 6~10 名员工信息
内层先排序生成结果集,再生成 rn,外层做区间过滤
select * from (
select e.*,rownum rn from (select * from employees order by salary desc) e
)
where rn>=6 and rn<=10;
十、表连接查询
多张表联合查询;查询字段分布在多张表时使用表连接。
1. 内连接 inner join
inner join:只返回满足连接条件的数据;连接字段为 null 的行会被过滤。
语法:
select ... from tab1 t1 inner join tab2 t2 on 连接条件;
案例:查询员工编号、姓名、工资、部门名称 表:employees、departments 连接条件:e.department_id = d.department_id
select e.employee_id,e.first_name,e.salary,d.department_name
from employees e inner join departments d
on e.department_id=d.department_id;
2. 外连接
①左外连接 left join【重点】
左表全部记录保留;右表匹配不到数据自动补 null;
outer关键字可以省略。
select e.employee_id,e.first_name,e.salary,d.department_name
from employees e left join departments d
on e.department_id=d.department_id;
②右外连接 right join
右表全部记录保留;左表匹配不到自动补 null。
select e.employee_id,e.first_name,e.salary,d.department_name
from employees e right join departments d
on e.department_id=d.department_id;
③全外连接 full outer join【了解】
两张表所有记录全部保留,匹配不到补 null
select e.*,d.*
from employees e full outer join departments d
on e.department_id=d.department_id;
④笛卡尔连接【了解】
不写连接条件,表的每一行互相全部配对,业务尽量避免。
select e.*,d.*
from employees e,departments d;
3. 多表连接查询【掌握】
需求:查询员工编号、姓名、工资、部门名称、部门所在城市 涉及表:employees、departments、locations
select e.employee_id,e.first_name,e.salary,d.department_name,l.city
from employees e
left join departments d on e.department_id=d.department_id
left join locations l on d.location_id=l.location_id;
多表连接执行逻辑:从左往右,先两张表连接,结果再和下一张表继续连接。