ORACLE知识总结
第二章——过滤与排序
一、SQL 的分类
1.DQL语句 (data quary language) select
2.DML语句 (数据操作语句)insert update delete
3.DDL语句 (数据定义语句)对数据库对象进行操作create alter drop truncate
4.DCL语句 (数据控制语句)对权限进行操作 grant revoke
5.TCL语句 (事物控制语句)commit rollback savepoint
二、简单的select语句
1、语法
select {*|列名|表达式} from 表名; *代表表中的所有列
注:Oracle中所有对象的名字都是不区分大小写的
例:查询employees表中所有列的数据
select * from employees;
例:查询employees表中员工的姓名和工资
select last_name||first_name,salary from employees;
例:查询emp表中员工姓名,工资以及年薪
select last_name,salary,salary*12 from employees;
注:遇到空值,先进行空值转换在进行计算,Oracle中的空值为null,是一个比较特殊的值,既不是空格也不是0,所有的数据类型都支持null。
1.如果null出现在算数表达式中,其结果一定为null
2.如果一个字符串连接一个null的话,其结果还是原来的字符串
2、列别名
写法有:列名 列别名 《==》 列名 as 列别名如果你的列别名中出现了空格等特殊字符的时候,需要写在双引号中如果要限制别名的大小写,也需要写在双引号中字符串使用“||”来连接字符串常量写在单引号中用单引号给单引号进行转义,也就是说在字符串中两个连续的单引号显示为一个单引号
练习:查询emp表的员工姓名和职位,
以 – XXX’s job is XXX
select last_name||'''s job_id is' ||job_id||null from employees;
3、去重复
distinct:去掉结果集中的重负记录
例:查询employees表中员工在那几个部门中工作,列出这些部门的编号
select distinct department_id from employees;
4、限制条件和给记录排序
1.格式:select 列名 from 表名 [where条件] [order by 列名|表达式|序号]
例:查询employees表中10号部门的员工信息
select * from employees where department_id = 10;
2.比较运算法有 “=”,“>”,“>=”,“<”,“<=”,“<>” 比较运算法两端的数据类型要一致
例:查询employees表中工资高于3000的员工信息
select * from employees where salary > 3000;
在表中存储的字符类型的数据是严格区分大小写的
例:查询employees表中姓名为Scott的员工信息
select * from employees where last_name = 'SCOTT';
3.日期类型的常量一定要写在单引号中
且Oracle中默认的日期格式是’DD-MON-YYYY’.
例:查询employees表中在1994年6月7日入职的员工信息
select * from employees where hire_date = '7-6月-94';
5、特殊的比较运算符
1.between and运算符
列名 between 值1 and 值2 <==> 列名>=值1 and 列名 <= 值2;
包括区间的端点,小得端点写在between后面,大的端点写在and后面
例:查询employees表中工资在5000到8000之间的员工信息(包括5000和8000)
select * from employees where salary between 5000 and 8000;
<==>
select * from employees where salary>=5000 and salary <=8000;
2.in运算符列名 in (值1,值2,值3,…); <==> 列名=值1 or 列名=值2 or…
例:查询employees表中在部门10,20,30部门工作的员工信息
select * from employees where department_id in (10,20,30);
<==>等价于
select * from employees where department_id = 10 or department_id = 20 or department_id = 30;
3.字符串的模糊匹配 like
通配符 “%”:可以代表任意长度的字符串,包括0长度 “_”:可以代表一个字符,不包括0长度
例:查询employees表中员工姓名以S开头员工信息
select * from employees where last_name like 'S%';
例:查询employees表中员工姓名第二个字符是o员工信息
select * from employees where last_name like '_o%';
例:查询employees表中员工姓名中至少含有一个E的员工信息
select * from employees where last_name like '%E%';
escape转义字符 可以用任意符号进行转义
例:查询employees表中职位以‘MK_’开头端点员工信息
select * from employees where job_id like 'MK+_%' escape '+';
<==>
select * from employees where job_id like 'MK\_%' escape '\';
4.is null 对空值的判断
例:查询employees表中没有绩效奖的员工信息
select * from employees where commission_pct is null;
空值只有is null或者is not null来判断的时候,才会返回true或false,否则后悔
返回null(不可知或不确定)
select * from employees where commission_pct = null;
5.not 运算符
列名 not between 值1 and 值2 《》列名 < 值1 or 列名 > 值2 列名 not in(值1,值2,值3,…) 《》 列名 <> 值1 and 列名 <> 值2 and 列名 <> 值3…
例:查询employees表中有绩效的员工的信息
select * from employees where commission_pct is not null;
例 :查询employees中10和20部门中工资小于6000的员工信息;
select * from employees where (department_id = 10 or department_id = 20) and salary < 6000;
例:查询employees表中job_id不是‘MK_’开头的员工信息
select * from employees where job_id not like 'MK!_%' escape '!';
三、排序
- 列名排序
例:查询employees表中30部门员工姓名和工资,要求按照工资进行降序排序
select last_name,salary from employees where department_id = 30 order by salary desc;
例:查询employees表中所有员工的姓名,工资和部门编号,要求按照部门升序,工资降序排序
select last_name,salary,department_id from employees order by department_id, salary desc;
- 表达式
例:查询employees表中所有员工的姓名,工资以及年薪,按照年薪升序排序
select last_name,salary,salary*12 from employees order by salary * 12 asc;
也可以根据列别名进行排序
select last_name,salary,salary*12 annsal from employees order by annsal asc;
- 序号 列在select子句中出现的位置-- 序号从1开始计数
例:查询employees表中所有员工的姓名,工资,职位和部门编号,要求按照部门升序,工资降序排序
select last_name,salary,job_id,department_id from employees order by 2,4;
第三章——单行行数
单行函数指的是对单行进行计算,也就是说会对结果集中每一条记录计算一次,每一条记录返回一个结果。
一、字符类型
1.大小写转换
例:把’I Love YOU’转换成全大写,全小写和首字符大写的形式
select upper('I Love YOU'),lower('I Love YOU'),initcap('I Love YOU') from dual;
2.concat(列|表达式,列|表达式):连接字符串
--例:把'I Love'和'You'连接起来
select concat('I Love','You') from dual;
--例:把'I','Love'和'You'连接起来
select concat(concat('I ', 'Love '), 'You') from dual;
函数嵌套,是由最内层向外层一次计算的,且单行函数可以无限嵌套
3.substr(列|表达式,m,n)
注:把源字符串中从第m位开始,截取n个字符,如果不写n,默认试试截取到字符串的末尾
--例:
select substr('I Love You',3,4) from dual;
例:将字符串’Hi, I am TOM, I am 15 years old, I Love YOU’中"YOU"截取出来(m可以取负数)
select substr('Hi, I am TOM, I am 15 years old, I Love YOU', -3, 3) from dual;--(从倒数第三个开始截取三位)
select substr('Hi, I am TOM, I am 15 years old, I Love YOU', -3) from dual;--(从倒数第三位开始截取到字符串的最后一个字符)
4.length(列|表达式):取长度
select length('Hi, I am TOM, I am 15 years old, I Love YOU') from dual;
5.instr(源字符串,子串,m,n)
注:返回子串在源字符串中从第m个字符开始,第n次出现的位置,m,n默认值都是1。
select instr('I Love You','o') from dual; --(表示第一次出现‘o’在第几位)
select instr('I Love You','o',5) from dual; --(表示从字符串的第5位开始,第1次出现‘o’的位置)
select instr('I Love You','o',5,1) from dual;--(表示从字符串的第5位开始,第1次出现‘o’的位置)
例:使用字符函数查询employees表的员工姓名,职位,以及工资,条件是:1、员工职位的最后三个字母是man 2、员工姓名中至少含有一个字母e
select last_name,job_id,alary from employees
where lower(substr(job_id, -3))='man' and instr(lower(last_name),'e')>0;
6.lapd(列|表达式,n,‘子串’):将源串用子串在左边填充成n个字符长度
rapd(列|表达式,n,‘子串’):将源串用子串在右边填充成n个字符长度
注:n指的是填充完的字符串的总长度,而不是填充多少个字符
例:将I Love You的左右分别用*填充到15个字符
select lpad('I Love You', 15, '*'), rpad('I Love You', 15, '*') from dual;
7.trim([leading|trailing|both]字符From源串):截去源串头|尾的字符–默认是both,头尾都截
--例:
select trim('l'from 'level') from dual;--——头尾都截
select trim(leading 'l' from 'level') from dual;--——只截头部
select trim(trailing 'l' from 'level') from dual;--——只截尾部
trim 的第二种用法:trim(列|表达式) ——去掉字符串头尾的空格
例:select ’ mike ’ 源串, trim(’ mike ')截后 from dual;
8.replace(源字符串,s1,s2):将源字符串中的s1都替换成s2
例:将‘I Love You’中的‘You’替换成‘Her’
select replace('I Love You','You','Her') from dual;
二、数字函数
1.round(列|表达式[,n]):将数字四舍五入到小数点后n位,n默认是0
--例:
select round(654.31,1) from dual; -- 四舍五入到小数点后一位
select round(654.31,-1) from dual; --四舍五入到小数点前一位
select ronnd(654.31) from dual; -- 四舍五入到0位小数
2.trunc(列|表达式[,n]):将数字截取到小数点后n位,n默认是0
--例:
select trunc(654.31,1) from dual; --截取到小数点后一位
select trunc(654.31,-3) from dual; -- 截取到小数点前三位
3.mod(m,n):计算m除以n后的余数
--例:
select mod(1000,400) from dual; --1000除以400=2*400+200,所以余数为200
4.abs(m):取绝对值
--例:
select abs(-654) from dual; --取-654的绝对值为654
三、日期函数
1.sysdate:返回当前系统(Oracle服务器)时间
--例:
select sysdate from dual;
2.months_between(date1,date2):返回两个日期之间相差的月数
例:查询employees中的员工至今为止已经在公司里工作了多少年了
Select last_name,hire_date,round(months_between(sysdate,hire_date)/12,1) from employees;
练习:计算自己的年龄,四舍五入到小数点后两位
select round(months_between(sysdate,'17-3月-00')/12,2) 年龄 from dual;
3.add_months(date1,n):在指定日期基础上加上 相对应的月数
--例:
select add_months(sysdate,1) from dual;
如果给定的日期是一个月的最后一天的话,加上对应月数,结果也是那个月的最后一天
--例:
select add_months('28-2月-2019',1) from dual;
- next_day(date1, ‘星期×’|n):返回给定日期后一周之内的下一个星期×的日期
注:是下一个星期几,不是下个星期几,比如今天星期四,next_day星期五就是明天
--例:
select next_day(sysdate,'星期二')from dual;
select next_day(sysdate,'星期五') from dual;
select next_day(sysdate,'星期四') from dual;
select next_day(sysdate,6) from dual;
– 星期日是一周的第一天,星期一是2,以此类推
- last_day(date1):返回指定日期当月最后一天的日期
--例:
select last_day(sysdate) from dual;
- round(date1, ‘fmt’): 对给定日期进行四舍五入fmt叫做格式
字符串,定了四舍五入到日期的哪一位代表年YYYY 表月 MM 代表日 DD
例:上半个月来,工资按全月发放,下半个月来,工资按下个月一号开始发放查询 employees表中员工从什么时间开始拿工资
select last_name,hire_date,round(hire_date,'mm') from employees;
– 1~15日为上半个月,不管这个月有多少天。
select round(to_date('15-2-2000', 'dd-mm-yyyy'), 'mm') from dual;
- trunc(date1, ‘fmt’): 对给定日期进行截断,fmt叫做格式字符串,规定了截断到日期的哪一位
例:不管上半个月或下半个月,工资全按全月发放。
select last_name,hire_date,trunc(hire_date,'mm') from employees;
- extract(year|month|day from date1) : 从指定的日期中抽取出年,月或日的信息
– year|month|day 都是关键字,不是字符串 – 是oracle 9i版本提供的,不建议大家使用
--例:
select extract(year from sysdate) from dual; --抽出年份
select extract(month from sysdate) from dual; -- 抽出月份
9.日期的数学运算
注:在日期上加上或者减去一个数字,结果仍为日期。
两个日期相减返回日期之间相差的天数(日期不允许做加法运算)。
可以用数字除以24来向日期中加上或者减去天数。
例:查询90号部门员工的姓名和到现在工作了多少个星期
select last_name,(sysdate-hire_date)/7 as weeks from employees where department_id = 90;
四. 类型转换
1、 隐式的类型转换
select * from employees where department_id = '10'; select * from employees where department_id = 10;
select * from employees where hire_date = '17-12月-1981'; ('DD-MON-YYYY')
– oracle是可以进行隐式类型转换的
– 隐式类型转换是有规则的
– 不建议大家使用隐式类型转换
– 1. 代码可读性差;
– 2. 使用隐式类型转换,代码的效率差;
– 3. Oracle并没有承诺在下一个版本中不修改隐式类型转换的规则。
2、 显式的类型转换
- to_char(date1|number1,‘fmt’) : 将日期或数字转换成字符,fmt是格式字符串,规定了转换的格式
– 常用的日期格式
– fm 去掉前导0
练习:输出当前系统日期,如 2011/4/11 星期一
select to_char(sysdate,'fmYYYY/MM/DD DY') from dual;
– 常用的时间格式
练习:输出当前系统时间,如 下午 3:24:33
select to_char(sysdate,'fmAM HH12:MI:SS') from dual; -- 获取到下午 几点几分几秒
– 如果在格式中需要加入字符串,那么这个字符串应该写在双引号中
练习:输出当前系统日期,如 2011年4月11日
select to_char(sysdate,'fmYYYY"年"MM"月"DD"日"') from dual;
– RR和YY的问题
– YY始终认为时间是当前世纪的时间
– RR更符合世纪之交人类的正常的思维习惯,有世纪转换。
`select to_char(sysdate,'WW') from dual;--当前时间是今年的第几周
– Q :代表季度
– W: 当月的第几周
– WW:当年的第几周
– 代表数字的格式字符串
– 9 : 代表一位数字;
– 0 : 代表一位数字或前导零;
– $ : 代表美元符号;
– L : 根据语言区域动态的显示本地的货币符号;
– . : 小数点;
– , : 千位分隔符;
例:查询employees表中King的姓名和工资,工资的格式要求有美元符号,带有千位分隔符,而且保留两位小数。
select last_name, to_char(salary,'$9,999.00') salary from employees where initcap(last_name) = 'King';
例子:查询employees表中King的姓名和工资,工资的格式要求有人民币符号,带有千
位分隔符,而且保留两位小数。(汇率是6)
select last_name, to_char(salary*6, 'L99,999,999.00') salary from employees where initcap(last_name) = 'King';
在数字向字符型转换的时候,整数位一定要足够长,否则的话结果出错 ‘17-12月-1981’
select * from employees where hire_date= to_date('12-17-1980', 'MM-DDYYYY');
五. 其他函数
- NVL (表达式1, 表达式2),两个参数的数据类型要一致。对第一个
参数进行判断,如果为空,则返回第二个参数的值,如果不为空,返回第一个参数
练习:查询employees表中员工姓名,工资以及年薪
select last_name,salary,(salary + nvl(commission_pct,0))* 12 from employees;
- nvl2(p1, p2, p3) : 对第一个参数进行判断,如果第一个参数不为
空的话,则返回第二个参数的值,如果为空的话,返回第三参数的值
练习:查询employees表中员工姓名,工资以及年薪
select last_name,salary,nvl2(commission_pct,salary + commission_pct , salary)*12 from employees;
-
NULLIF(表达式1, 表达式2): 函数主要是完成两个参数的比较。当两个参数不相等时,返回值是第一个参数值;当两个参数相等时,返回值是空值。
-
Coalesce(p1, p2…):参数的数量没有限制,返回第一个不为空的参数
练习:查询employees表中员工姓名,工资以及年薪
select last_name,salary,coalesce(salary+commission_pct,salary,0) * 12 from employees;
5.Case:作条件分支的判断 Case 列|表达式 When 取值1 Then 返回值1 When 取值2 Then 返回值2…When 取值N Then返回值N Else默认返回值End
练习:查询employees表中员工的姓名,部门编号以及部门名称(10 - 部门1)
select last_name,department_id,
(case department_id
when 10 then '部门1'
when 20 then '部门2'
else '部门3' end)部门名称
from employees;
decode : case表达式的简便写法
– decode函数的参数也是不限数量的 decode(列|表达式, 取值1, 返 回值1, 取值
2, 返回值2,…取值N, 返回值N, 默认返回值)
练习:查询公司在1995-1998年之间,每年雇用的人数 to_char count
select count(*) total, sum(decode(to_char(hire_date,'yyyy'),1995,1,0))"1995", sum(decode(to_char(hire_date,'yyyy'),1996,1,0))"1996", sum(decode(to_char(hire_date,'yyyy'),1997,1,0))"1997", sum(decode(to_char(hire_date,'yyyy'),1998,1,0))"1998" from employees;
用 group by 和having来写
select to_char(hire_date,'yyyy') 年份,count(employee_id) 人数 from employees group by to_char(hire_date,'yyyy')
having to_char(hire_date,'yyyy') in (1995,1996,1997,1998);
用case when then else end来写
select count(*) as total, count (case when to_char(hire_date,'yyyy')=1995 then 1995 else null end) "1995"
,count(case when to_char(hire_date,'yyyy')=1996 then 1996 else null end) "1996"
,count(case when to_char(hire_date,'yyyy')=1997 then 1997 else null end) "1997"
,count(case when to_char(hire_date,'yyyy')=1998 then 1998 else null end) "1998" from employees;
第四章——多表查询
一、笛卡尔集
注:笛卡尔集会省略连接条件,所有表中的所有行互相连接
例:查询员工姓名和相对应的部门名称
select last_name||first_name as 姓名,department_name from employees ,departments where employees.department_id = departments.department_id;
–当不写where语句时,出现的结果是员工数*部门数,写where语句,也可以说成
Oracle连接
二、表的连接
1.等值连接
注:连接条件使用“=”进行比较,其他的筛选条件和连接条件之间是“and”的关系
例:查询employees表中,工资高于2000员工的姓名和部门名称
select e.last_name||first_name,d.department_name as from employees e ,departments d s where d.department_id = e.department_id and e.salary>2000;
– 只要在SQL中给表起了别名了,那么在SQL语句的任何地方都不能再使用表名引用其中的列,建议大家所有的列都要加上表名作为前缀
2.不等值连接
注:连接条件不用“=”连接
例:查询employees表中员工的工资以及工资等级
select e.last_name||first_name,e.salary,j.grade_level from employees e,job_grades j where e.salary
between j.lowest_sal and j.highest_sal
–使用表名前缀在多个表中区分相同的列。在不同表中具有相同列名的列可以用表的别名加以区分。使用别名可以简化查询.使用表名前缀可以提高执行效率
3.外连接
注:使用外连接可以查询不满足条件的数据,外连接符号是“(+)”写在连接条件中,且外连接符号“(+)”永远是放在连接条件的缺乏表的一端,你要接触哪个表的所以记录,另外一张表就是缺乏表
例:查询各部门有哪些员工工作,即使这个部门没有员工 .(右外连接)
select d.department_name, e.last_name from employees e, departments d where e.department_id(+) = d.department_id;
例:查询employees表员工姓名和部门名称,即使这个员工没有部门。(左外连接)
select d.department_name,e.last_name||first_name from employees e,departments d where e.department_id=d.department_id(+);
例:查询emp表员工姓名和部门名称,即使这个部门没有员工,即使这个员工没有部门。(全外连接)
select d.department_name,e.last_name from employees e full outer join departments d on e.department_id=d.department_id;
注:上面这种写法是SQL1999写法
例:输出没有员工的部门名称
select d.department_name from employees e,departments d
where e.department_id(+)=d.department_id and e.last_name is null
注:内连接: 合并具有同一列的两个以上的表的行, 结果集中不包含一个表与另一个表不匹配的行
外连接: 两个表在连接过程中除了返回满足连接条件的行以外还返回左(或右)表中
不满足条件的行 ,这种连接称为左(或右) 外连接。没有匹配的行时, 结果表中相应的列为空(NULL). 外连接的 WHERE 子句条件类似于内部连接, 但连接条件中没有匹配行的表的列后面要加外连接运算符, 即用圆括号括起来的加号(+).
四、自连接
注:查询结果和查询条件都需要从同一张表中查询出来的这种问题,需要使用到自连接
例:查询和King同部门的员工的信息,但是不包括King
select e1.* from employees e1, employees e2 where e1.department_id = e2.department_id and e2.last_name = 'King' and e1.last_name <> 'King';
–自连接的语法比较晦涩,在工作中很少用到。
–一般用子查询来代替自连接。
五:SQL1999连接语法
1.交叉连接(t1 cross join t2)–就是生成两个表的笛卡尔集
例:查询员工姓名和相对应的部门名称
select e. last_name, d.department_name from employees e cross join departments d;
2.自然连接(t1 natural join t2)
注:NATURAL JOIN 子句,会以两个表中具有相同名字的列为条件创建等值连接。
在表中查询满足等值条件的数据。
如果只是列名相同而数据类型不同,则会产生错误。
返回的是,两个表中具有相同名字的列的“且、交集”,而非“或,并集”。即:比如
employee类和department类都有department_id和manager_id,返回二者都相同的结果。
例:自然连接,自动查找两个表的公共字段(狭义的公共字段,列名和数据类型都相同的那些列)作为连接条件进行等值连接
select e.last_name,d.department_name from employees e natural join departments d;
3.等值连接(t1 join t2 using(列名))
注:在“NATURAL JOIN”子句创建等值连接时,可以使用“USING”子句指定等值连接中需要用到的列。使用 USING 可以在有多个列满足条件时进行选择。
不要给选中的列中加上表名前缀或别名。
JOIN 和 USING 子句经常同时使用。
例:用户指定的公共字段列进行等值连接
Select e.last_name,d.department_name from employees e join departments d using(department_id);
4.连接条件(table1 join table2 on (连接条件))
注:自然连接中是已具有相同名字的列为连接条件的。
可以使用ON字句指定额外的连接条件。这个连接条件是与其他条件分开的。
ON字句是语句具有更高的易读性。
例:由用户指定连接条件进行连接,通常解决两个表没有狭义的公共字段或两个表需要使用不等值连接的情况
select e.last_name,d.department_name from employees e join departments d on (e.department_id = d.department_id);
例:使用ON字句创建多表连接
select employee_id, city, department_name from employees e
join departments d on d.department_id = e.department_id
join locations l on d.location_id = l.location_id;
5.外连接(t1 left/right/full outer join t2 on(连接条件))
注:在SQL:1999中,内连接值返回满足里阿杰条件的数据。
两个表在连接过程中除了返回满足连接条件的行以外,还返回左或右表中不满足条件的行,这种连接成为左或右外连接。
两个表在连接过程中除了返回满足连接条件的行以外,还返回两个表中不满足条件的行,这种连接成为满外连接。
例:查询各部门有哪些员工工作,即使这个部门没有员工¬
左外连接写法:
select d.department_name,e.last_name
from departments d left outer join employees e on (d.department_id = e.department_id);
右外连接写法:
select d.department_name,e.last_name from employees e
right outer join departments d on(d.department_id = e.department_id);
满(全)外连接写法:
例:查询employees表员工姓名和部门名称,即使这个部门没有员工,即使这个员工没有部门。(全外连接)
select d.department_name,e.last_name from employees e full outer join departments d on(d.department_id = e.department_id);
第五章——分组函数
分组函数会对结果集中一组记录计算一次,一组记录返回一个结果。
一、常用的分组函数
1.max([distinct]列|表达式) min([distinct]列|表达式):返回的结果集中某列的最大值或最小值
例:查询10部门中工资的最大值和最小值分别是多少
select max(salary),min(salary) from employees where department_id = 10;
2.sum([distinct]列|表达式):计算结果集中某列数值之和
例:计算10部门中员工的工资总数是多少
select sum(salary) from employees where department_id = 10;
3.avg([distinct]列|表达式):计算结果集中的某列数值的平均值
例:查询10部门中员工的平均工资
select avg(salary) from employees where department_id;
4.count([distince]*|列名):返回结果集中记录的条数
例:查询10号部门中员工的数量
select count(*) from employees where department_id = 10;
5.distince关键词的用法
例:查询employees表中的员工在几个部门工作
select count(distince department_id) from employees;
6.group by 子句
1.分组函数通常和group by子句联用,group by子句提供了一个分组的依据 group by子句中出现的列,可以不再select子句中出现
例:查询employees表中各部门员工粽子对的最大值、最小值、总和和平均值
select department_id,max(salary),min(salary),sum(salary),avg(salary) from employees group by department_id;
2.select子句中出现的非分组函数列,一定要在group by子句中出现
例:查询employees表中平均工资高于2000的部门编号个平均工资
select department_id,avg(salary) from employees
--where avg(salary)>2000 group by department_id
having avg(salart)>2000
– having 子句:对分组函数的结果进行筛选,是SQL语句的执行顺序所决定的
– where 子句中不能出现分组函数
例:查询employees表中领导的员工编号以及下属员工的数量
select manager_id,count(*) from employees group by manager_id having manager_id is not null;