首页 > 代码库 > SQL查询

SQL查询

1. SQL基础查询

1.1 基本查询语句

? SELECT

用于指定要查询的列,如果要查询所有列,在SELECT后面使用“*”号表示,如果查询特定的列,可以直接后面跟指定的列名,列名之间用”,”逗号隔开。

演示:查询所有列

SELECT * FROM dept;

技术分享

演示:查询具体列

SELECT ename,sal FROM emp;

技术分享

? FROM

表示从哪张表查询内容,案例如上。

? AS

用于给列名起别名,或者表示计算结果的含义,也可以不加AS关键字。

演示:查看员工一年薪资并起别名为Salary

SELECT empno AS id,sal*12 "Salary" FROM emp;

技术分享

? WHERE

表示条件查询,当查询条件中和数字比较时,可以使用单引号引起也可以不用。当和字符及日期类型的数据比较,则必须用单引号引起。

演示:和数字比较

SELECT ename,sal FROM emp WHERE sal >1000; --不加单引号

SELECT ename,sal FROM emp WHERE sal>‘1000‘; --加单引号

技术分享

演示:和字符及日期比较

SELECT ename,sal FROM emp WHERE ename=‘MARTIN‘;

技术分享

演示:和日期比较

SELECT ename,hiredate FROM emp WHERE hiredate=‘17-12月-80‘;

技术分享

1.2 查询条件

? >,<,>=,<=,!=,<>,=

在WHERE子句中,可以使用比较运算符来做查询。

!=和<>都表示不等于,一般<>比较常用。

演示:查询部门号不是10的员工

SELECT ename,deptno FROM emp WHERE deptno!=10;

SELECT ename,deptno FROM emp WHERE deptno<>10;

技术分享

? AND,OR

l AND表示且

l OR表示或

演示:查询薪资大于1000并且职位是CLERK的员工

SELECT ename,sal,job FROM emp WHERE sal>1000 AND job=‘CLERK‘;

技术分享

演示:查询薪资大于1000或职位是CLERK的员工

SELECT ename,sal,job FROM emp WHERE sal>1000 OR job=‘CLERK‘;

技术分享

? LIKE

模糊查询,需要借助两个通配符:

l %:表示0到多个字符

l _:表示单个字符

演示:查询姓名第二个字符是A的员工信息

SELECT * FROM emp WHERE ename LIKE ‘_A%‘;

技术分享

? IN,NOT IN

在WHERE子句中可以用比较操作符IN(list)来取出符合列表范围中的数据,其中list表示值列表,当列或表达式匹配于列表中任何一个值时,条件为TRUE,该条记录被显示出来。

NOT IN(list)表示取出不符合此列表中的数据记录。

演示:查询职位是MANAGE和CLERK的员工

SELECT ename,sal,job FROM emp WHERE job IN (‘MANAGER‘,‘CLERK‘);

技术分享

演示:查询部门不是10和20的员工

SELECT ename,sal,deptno FROM emp WHERE deptno NOT IN (10,20);

技术分享

? BETWEEN...AND...

用来查询符合某个范围条件的数据,通常用在数字类型的数据范围上,对字符类型和日期类型也同样适用。

演示:查询薪资在1500到3000内的员工

SELECT ename,sal FROM emp WHERE sal BETWEEN 1500 AND 3000;

技术分享

? IS NULL,IS NOT NULL

NULL空值比较的时候,不能使用“=”号,需要使用IS NULL或IS NOT NULL。

演示:查询绩效为NULL的员工

SELECT ename,comm FROM emp WHERE comm IS NULL;

技术分享

? ANY,ALL

在比较运算符中,ANY表示任意一个满足条件,ALL表示全部满足条件,需要配合运算符来使用。

l >ANY:大于最小

l <ANY:小于最大

l >ALL:大于最大

l <ALL:小于最小

演示:查询薪资大于1000或1500的员工(即薪资大于1000的)

SELECT ename,sal FROM emp WHERE sal>ANY(1000,1500);

技术分享

演示:查询薪资小于1000或1500的员工(即薪资小于1500的)

SELECT ename,sal FROM emp WHERE sal<ANY(1000,1500);

技术分享

演示:查询薪资大于1000和1500的员工(即薪资大于1500的)

SELECT ename,sal FROM emp WHERE sal>ALL(1000,1500);

技术分享

演示:查询薪资小于1000和1500的员工(即薪资小于1000的)

SELECT ename,sal FROM emp WHERE sal<ALL(1000,1500);

技术分享

演示:查询薪资比职位是“SALEMAN“的人高的员工信息,即比任意一个SALEMAN薪资高的员工

SELECT ename,sal

FROM emp

WHERE sal>ANY(SELECT sal FROM emp WHERE job=‘SALESMAN‘);

技术分享

? 表达式和函数

在查询时,可以使用算术表达式(+-*/),表达式符合四则运算的默认优先级,改变优先级可以使用括号。算术运算主要针对数字类型的数据,对日期也有效,表示在一个日期值上加或减多少天。

查询条件中使用字符串函数UPPER,将条件的字符串转换大写后再比较。

演示:查询年薪大于10万并且姓名是WARD的员工信息

SELECT * FROM emp WHERE sal*12>10000 AND ename=UPPER(‘ward‘);

技术分享

? DISTINCT

用来过滤重复,数据表中有可能存储相同数据的行,当执行查询操作时,默认情况会显示所有行,不管查询结果是否有重复数据。当重复数据没有实际意义,经常需要去掉重复值。

演示:查询员工的部门编码有哪些

SELECT DISTINCT deptno FROM emp;

技术分享

演示:查询员工的部门编码和职位有哪些

SELECT DISTINCT deptno,job FROM emp;

技术分享

提示:这样表示deptno和job组合起来的不重复。

1.3 排序

? ORDER BY

对查询出的数据按一定规则进行排序操作,默认按升序排列。需要注意的是ORDER BY必须出现在SELECT中的最后一个子句。

演示:对职员薪资进行排序

SELECT ename,sal FROM emp ORDER BY sal;

技术分享

? ASC,DESC

l ASC:按升序排列

l DESC:按降序排列

注意:NULL值视为最大,如果不写ASC或DESC则默认为ASC。

演示:员工绩效降序排列

SELECT ename,comm FROM emp ORDER BY comm;

技术分享

? 多列排序

当多列作为排序标准时,首先按照第一列进行排序,如果第一列数据相同,再以第二列排序,以此类推。多列排序不管正序还是倒序,每个列都需要单独设置排序方式。

演示:按部门绩效升序和薪资降序排序

SELECT ename,comm,sal FROM emp ORDER BY comm ASC,sal DESC;

技术分享

演示:按comm和sal默认排序

SELECT ename,comm,sal FROM emp ORDER BY comm,sal;

技术分享

1.4 聚合函数

查询时需要做一些数据统计,如查询职员表中各部门职员的平均薪水,员工人数等。当需要统计的数据并不能在职员表里直观列出,而是需要根据现有的数据计算得到结果,这种功能可以使用聚合函数来实现,即:将表的全部数据划分为几组数据,每组数据统计出一个结果。

因为是多行数据参与运算返回一行结果,也称为分组函数、多行函数、集合函数。关键字如下:

l GROUP BY:按什么分组

l HAVING:进一步限制分组结果

? MAX,MIN

用来取得列或表达式的最大、最小值,可以用来统计任何数据类型,包括数字、字符和日期。

演示:获取10部门中工资最高和最低是多少

SELECT MAX(sal),MIN(sal) FROM emp WHERE deptno=10;

技术分享

演示:获取入职日期最晚和最早的

SELECT MAX(hiredate),MIN(hiredate) FROM emp;

技术分享

? AVG,SUM

l AVG:统计列或表达式的平均值

l SUM:统计列或表达式的和

注意:这两个函数只能操作数字类型,并忽略NULL值。

演示:获取平均工资和工资总和

SELECT AVG(sal),SUM(sal) FROM emp;

技术分享

? COUNT

用来计算表中的记录条数,同样忽略NULL值。

演示:获取一共有多少员工

SELECT COUNT(*) AS total_emp FROM emp;

技术分享

? NULL值处理

聚合函数忽略NULL值,即当emp表中comm列有NULL值就被忽略。

演示:列出平均绩效,忽略NULL值

SELECT AVG(comm),SUM(comm),COUNT(sal) FROM emp;

技术分享

可以看出,这个平均绩效是不对的,因为NULL值被忽略了。

演示:列出平均绩效不忽略NULL值

SELECT AVG(NVL(comm,0)),SUM(comm),COUNT(sal) FROM emp;

技术分享

1.5 分组

? GROUP BY

用于分组。

演示:查询每个部门的员工数

SELECT COUNT(*),deptno FROM emp GROUP BY deptno;

技术分享

演示:查询同部门同职位的员工数

SELECT COUNT(*),deptno,job FROM emp GROUP BY deptno,job;

技术分享

演示:查询每个部门的平均工资

SELECT AVG(sal),deptno FROM emp GROUP BY deptno;

技术分享

演示:查询平均工资高于2000的部门

SELECT deptno FROM emp WHERE AVG(sal)>2000 GROUP BY deptno; --错误

原因:因为WHERE中是不能使用聚合函数作为过滤条件的,原因在于过滤的时机不对,WHERE是在检索表中数据时逐行进行过滤的,将满足条件的记录查询出来生成结果集,聚合函数是用来统计结果集中的数据,所以要先将数据查询出来才可以进行,为此用聚合函数的结果是在WHERE之后进行的,这就需要用到下面的HAVING子句。

? HAVING

用来对分组后的结果进一步限制,必须跟在GROUP BY后面,不能单独存在。

演示:查询平均工资高于2000的部门

SELECT AVG(sal),deptno FROM emp GROUP BY deptno HAVING AVG(sal)>2000;

技术分享

演示:查看每个部门的最高薪资且将大于4000的显示出来

SELECT MAX(sal) FROM emp GROUP BY deptno HAVING MAX(sal)>4000;

技术分享

? 查询语句执行顺序

当一条查询语句中包含所有的子句,执行的顺序依照下列子句的次序:

l FROM子句:执行顺序从后往前,从右往左。数据量较少的表尽量放在后面

l WHERE子句:执行顺序从上往下,从右往左。将能过滤掉最大数量记录的条件写在WHERE子句的最右

l GROUP BY:执行顺序从左往右分组,最好在GROUP BY前使用WHERE将不需要的记录在GROUP BY之前过滤

l HAVING子句:消耗资源,尽量避免使用,HAVING会在检索出所有记录之后才对结果集进行过滤,需要排序等操作

l SELECT子句:少用*号,尽量取字段名。Oracle在解析的过程中,通过查询数据字典将*号依次转换成所有的列名,消耗时间。

l ORDER BY子句:执行顺序从左往右,消耗资源

2. SQL关联查询

2.1 关联基础

实际应用中需要的数据经常会需要查询两个或两个以上的表,这种查询两个或两个以上数据表或视图的查询叫做连接查询,连接查询通常建立在存在相互关系的父子表之间。

演示:查询在NEW YORK工作的员工

SELECT ename,loc FROM emp,dept WHERE emp.deptno=dept.deptno AND loc=‘NEW YORK‘;

技术分享

? 笛卡尔积

笛卡尔积指做关联操作的每个表的每一行都和其它表的每一行做组合,即缺少关联查询条件的时候产生。

演示:笛卡尔积

SELECT ename,loc FROM emp,dept;

技术分享

? 等值相连

等值连接是连接查询中最常见的一种,通常是在有主键关联关系的表间建立,将连接条件设定为有关系的列,使用等号“=”连接相关的表。

演示:查看部门号是10并且在

SELECT ename,deptno,loc FROM emp,dept WHERE emp.deptno=dept.deptno AND loc=‘NEW YORK‘; --错误

原因:未明确定义列,即deptno不明确,因为两个表中都有deptno列,所以关联查询一般需要使用到别名。

SELECT e.ename,e.deptno,d.loc FROM emp e,dept d WHERE e.deptno=d.deptno AND d.loc=‘NEW YORK‘;

技术分享

2.2 关联查询

? 内连接

内连接返回两个关联表中所有满足连接条件的记录。

演示:查询员工的姓名和所在部门的名字

SELECT e.ename,d.dname FROM emp e,dept d WHERE e.deptno=d.deptno;

或者写成下面形式:

SELECT e.ename,d.dname FROM emp e JOIN dept d ON(e.deptno=d.deptno);

技术分享

? 外连接

外连接不仅返回满足连接条件的记录,还将返回不满足连接条件的记录。外连接分为:左外连接、右外连接、全外连接。

l 左外连接:左外连接:以 JOIN 左侧表作为驱动表(所有数据都要显示的表),那么当驱动表中某条记录不满足连接条件时则右侧表中的字段全部取值为NULL。

l 右外连接:以 JOIN 右侧表作为驱动表(所有数据都要显示的表),那么当驱动表中某条记录不满足连接条件时则右侧表中的字段全部取值为NULL。

l 全外连接:以 JOIN 两侧表作为驱动表(所有数据都要显示的表),那么当驱动表中某条记录不满足连接条件时则右侧表中的字段全部取值为NULL,即左外连接与右外连接的总和。

演示:左外连接

SELECT e.ename,d.dname FROM emp e LEFT OUTER JOIN dept d ON e.deptno=d.deptno;

或者

SELECT e.ename,d.dname FROM emp e,dept d WHERE e.deptno=d.deptno(+); --左外连接,+号在哪,那边写NULL

技术分享

演示:右外连接

SELECT e.ename,d.dname FROM emp e RIGHT OUTER JOIN dept d ON e.deptno=d.deptno;

或者:

SELECT e.ename,d.dname FROM emp e,dept d WHERE e.deptno(+)=d.deptno; --右外连接

技术分享

这里有个NULL值是因为没有员工是40号部门的。

演示:全外连接

SELECT e.ename,d.dname FROM emp e FULL OUTER JOIN dept d ON e.deptno=d.deptno;

技术分享

? 自连接

自连接是一种特殊的连接查询,数据的来源是一个表,即关联关系来自于单表中的多个列,表中的列参照同一个表中的其它列的情况称作自参照表。自连接是通过将表用别名虚拟成两个表的方式实现,可以是等值或不等值连接。

演示:查询每个员工以及其上司的名字

SELECT e1.ename,e2.ename FROM emp e1,emp e2 WHERE e1.mgr=e2.empno(+);

或者:

SELECT e1.ename,e2.ename FROM emp e1 JOIN emp e2 ON e1.mgr=e2.empno(+);

技术分享

3. SQL高级查询

3.1 子查询

子查询:嵌入在其它SQL语句中的SELECT语句,大部分情况出现在WHERE子句中。子查找嵌入的语句称作主查询或父查询。主查询可以是SELECT语句,也可以是其它类型的语句,如DML或DDL语句。

根据返回结构的不同,子查询可以分为单行子查询、多行子查询和多列子查询。

? 子查询在WHERE子句中

案例:查询和SCOTT同职位的员工

SELECT ename,job

FROM emp

WHERE job=

(SELECT job FROM emp WHERE ename=‘SCOTT‘);

技术分享

案例:查询薪水比整个机构平均薪水高的员工

SELECT ename,sal FROM emp WHERE sal>(SELECT AVG(sal) FROM emp);

技术分享

注意:如果子查询返回多行,主查询中要使用多行比较符,包括IN、ALL、ANY。其中ALL和ANY不能单独使用,需要配合单行比较操作符>、>=、<、<=一起使用,如下案例。

案例:查询部门中有SALESMAN但职位不是SALESMAN的员工信息

SELECT empno,ename,job,deptno

FROM emp

WHERE deptno IN

(SELECT deptno FROM emp WHERE job=‘SALESMAN‘)

AND job<>‘SALESMAN‘;

技术分享

注意:在子查询中需要引用到主查询的字段数据,使用EXISTS关键字。EXISTS后边的子查询至少返回一行数据,则整个条件返回TRUE。如果查询没有结果,则返回FALSE,如下案例。

案例:查询哪些有员工的部门信息

SELECT deptno,dname

FROM dept d

WHERE EXISTS

(SELECT * FROM emp e WHERE d.deptno=e.deptno );

技术分享

? 子查询在HAVING部分

案例:查询最低薪水高于部门30的最低薪水的部门信息

SELECT deptno,MIN(sal)

FROM emp

GROUP BY deptno

HAVING MIN(sal)>

(SELECT MIN(sal) FROM emp WHERE deptno=30);

技术分享

? 子查询在FROM部分

在查询语句中,FROM子句用来指定要查询的表。如果在一个子查询的结果中继续查询,则子查询出现在FROM子句中,这个子查询也称作行内视图或匿名视图。这时把子查询当做视图对待,但视图没有名字,只能在当前SQL语句中有效。

案例:查询薪水比本部门平均薪水高的员工信息

SELECT e.deptno,e.ename,e.sal

FROM emp e,

(SELECT deptno,AVG(sal) avg_sal FROM emp GROUP BY deptno) x

WHERE e.deptno=x.deptno

AND e.sal>x.avg_sal

ORDER BY e.deptno;

技术分享

? 子查询在SELECT部分

把子查询放在SELECT子句部分,可以认为是外连接的另一种表现形式,使用更灵活。

案例:

SELECT e.ename,e.sal,e.deptno,

(SELECT d.deptno FROM dept d

WHERE d.deptno=e.deptno) deptno

FROM emp e;

技术分享

3.2 分页查询

? ROWNUM

ROWNUM被称为伪列,用于返回标识行数据顺序的数字。

案例:

SELECT ROWNUM,empno,ename,sal FROM emp;

技术分享

注意:ROWNUM只能从1开始计数,不能从结果集中直接截取,如下案例。

案例:查询ROWNUM大于3的列

SELECT ROWNUM,empno,ename,sal FROM emp WHERE ROWNUM>3;

因为从1开始,所以查询大于3或者等于3的列都没有内容,但是可以查询小于3的列。

SELECT ROWNUM,empno,ename,sal FROM emp WHERE ROWNUM<3;

技术分享

如果需要利用ROWNUM截取结果集中的部分数据,需要用到行内视图。

案例:查询8-10列的信息

SELECT * FROM

(SELECT ROWNUM rn,e.*FROM emp e)

WHERE rn BETWEEN 8 AND 10;

技术分享

? 使用子查询进行分页

分页策略是指每次只读取一页的数据。每次换页,取下一页的数据。在Oracle中利用ROWNUM功能来分页。

分页查询公式:PageN:(n-1)*pageSize+1至n*pageSize

? 分页与ORDER BY

案例:按薪水倒序排列,取出结果集中第8到第10条记录

SELECT * FROM

(SELECT ROWNUM rn,t.* FROM

(SELECT empno,ename,sal FROM emp

ORDER BY sal DESC) t

)

WHERE rn BETWEEN 8 AND 10;

技术分享

3.3 DECODE函数

? DECODE函数基本语法

DECODE函数语法:

DECODE (expr, search1, result1[, search2, result2…][, default])

用于比较参数expr的值,如果匹配到哪一个search条件,就返回对应的result结果,可以有多组search和result的对应关系,如果任何一个search条件都没有匹配到,则返回最后default的值。default参数是可选的,如果没有提供default参数值,当没有匹配到时,将返回NULL。

案例:查询职员表,根据职员的职位计算奖励金额,当职位分别是’MANAGER’、’ANALYST’、’SALESMAN’时,奖励金额分别是薪水的1.2倍、1.1倍、1.05倍,如果不是这三个职位,则奖励金额取薪水值

SELECT ename,job,sal,

DECODE(job,‘MANAGER‘,sal*1.2,

‘ANALYST‘,sal*1.1,

‘SALESMAN‘,

sal*1.5,

sal

) bonus

FROM emp;

技术分享

和DECODE函数功能相似的有CASE语句,实现类似于if-else的操作。

SELECT ename,job,sal,

CASE job WHEN ‘MANAGER‘ THEN sal*1.2

WHEN ‘ANALYST‘ THEN sal*1.1

WHEN ‘SALESMAN‘ THEN sal*1.5

ELSE sal END

bonus

FROM emp;

? DECODE函数在分组查询中的应用

OECODE函数可以按字段内容分组。

案例:计算职位的人数,analyst/manager职位属于vip,其余是普通员工operation,这种功能无法用GROUP BY简单实现。用decode的实现方式

SELECT DECODE(job,‘ANALYST‘,‘VIP‘,

‘MANAGER‘,‘VIP‘,

‘OPERATION‘) job,

COUNT(1) job_cnt

FROM emp

GROUP BY DECODE(job,‘ANALYST‘,‘VIP‘,‘MANAGER‘,‘VIP‘,‘OPERATION‘);

技术分享

DECODE函数也可以按字段内容排列。

案例:Dept表中按”研发部”、“市场部”、“销售部”排序,用普通的select语句,无法按照字面数据排序

SELECT deptno,dname,loc

FROM dept

ORDER BY

DECODE(dname,‘研发部‘,1,‘市场部‘,2,‘销售部‘,3),loc;

技术分享

3.4 排序函数

? ROW_NUMBER

语法:

ROW_NUMBER() OVER(PARTITION BY col1 ORDER BY col2);

表示根据col1分组,在分组内部根据col2排序。此此函数计算的值就表示每组内部排序后的顺序编号,组内连续且唯一。

ROWNUM是伪列, ROW_NUMBER功能更强,可以直接从结果集中取出子集。

案例:按照部门编码分组显示,每组内按职员编码排序,并赋予组内编码

SELECT deptno,ename,empno,

ROW_NUMBER()

OVER(PARTITION BY deptno ORDER BY empno) AS emp_id

FROM emp;

技术分享

? RANK

语法:

RANK() OVER(PARTITION BY col1 ORDER BY col2);

表示根据col1分组,在分组内部根据col2排名,相同的数据返回相同排名。特点是跳跃排序,如果有相同数据,则排名相同,比如并列第二,则两行数据都标记为2,但下一位排名是第四名。

和ROW_NUMBER的区别是结果有重复值,而ROW_NUMBER没有。

案例:按照部门编码分组,同组内按薪水倒序排序,相同薪水则按奖金数正序排序,并给予组内等级,用Rank_ID表示

SELECT deptno,ename,sal comm,

RANK() OVER (PARTITION BY deptno

ORDER BY sal DESC,comm) "Rank_ID"

FROM emp;

技术分享

? DENSE_RANK

语法:

DENSE_RANK() OVER(PARTITION BY col1 ORDER BY col2);

表示根据col1分组,在分组内部根据col排名,相同的数据返回相同排名。特点是连续排序,如果有并列第二,下一个排序将是3,这一点是和RANK的不同,RANK是跳跃排序。

案例:关联emp和dept表,按照部门编码分组,每组内按照员工薪水排序,列出员工的部门名字、姓名、薪水

SELECT d.dname,e.ename,e.sal,

DENSE_RANK()

OVER (PARTITION BY e.deptno ORDER BY e.sal)

AS drank

FROM emp e join dept d ON e.deptno = d.deptno;

技术分享

3.5 高级分组函数

ROLLUP、CUBE、GROUPING SETS运算符是GROUP BY子句的扩展,可以生成与使用UNION ALL来组合单个分组查询时相同的结果集,用来简化和高效的实现统计查询。

语法:

l GROUP BY ROLLUP(a,b,c)

l GROUP BY CUBE(a,b,c)

l GROUP BY GROUPING SETS(a,b,c)

? ROLLUP

案例:

SELECT ename,deptno,comm,SUM(sal)

FROM emp

GROUP BY ROLLUP(ename,deptno,comm);

等价于:

SELECT ename,deptno,comm,SUM(sal) FROM emp GROUP BY ename,deptno,comm

UNION ALL

SELECT ename,deptno,NULL,SUM(sal) FROM emp GROUP BY ename,deptno

UNION ALL

SELECT ename,NULL,NULL,SUM(sal) FROM emp GROUP BY ename

UNION ALL

SELECT NULL,NULL,NULL,SUM(sal) FROM emp;

技术分享

对ROLLUP的列从右到左以一次少一列的方式进行分组知道所有列都去掉后的分组(也就是全表分组)。对于n个参数的ROLLUP有n+1次分组。

? CUBE

语法:

GROUP BY CUBE(a,b,c)

对于CUBE的每个参数,都可以理解为取值为参与分组和不参与分组两个值的一个维度,所有维度取值组合的集合就是分组后的集合,对于n个参数的CUBE有2的n次方分组。

如果GROUP BY CUBE(a,b,c),首先对(a,b,c)进行GROUP BY,然后依次是(a,b),(a,c),(a),(b,c),(b),(c),最后对全表进行GROUP BY操作,所以一共是2^3=8次分组。

SELECT a,b,c,SUM(d) FROM test GROUP BY CUBE(a,b,c);

等价于:

SELECT a,b,c,SUM(d) FROM test GROUP BY a,b,c

UNION ALL

SELECT a,b,NULL,SUM(d) FROM test GROUP BY a,b

UNION ALL

SELECT a,NULL,c,SUM(d) FROM test GROUP BY a,c

UNION ALL

SELECT a,NULL,NULL,SUM(d) FROM test GROUP BY a

UNION ALL

SELECT NULL,b,c,SUM(d) FROM test GROUP BY b,c

UNION ALL

SELECT NULL,b,NULL,SUM(d) FROM test GROUP BY b

UNION ALL

SELECT NULL,NULL,c,SUM(d) FROM test GROUP BY c

UNION ALL

SELECT NULL,NULL,NULL,SUM(d) FROM test ;

虽说运行结果等价,但其内部运行机制不同,其效率远高于UNION ALL。

? GROUPING SETS

GROUPING SETS运算符可以生成与使用单个GROUP BY、ROLLUP或CUBE运算符所生成的结果集相同的结果集,但是使用更灵活。

如果不需要获得由完备的 ROLLUP 或 CUBE 运算符生成的全部分组,则可以使用 GROUPING SETS 仅指定所需的分组。GROUPING SETS 列表可以包含重复的分组。

分组方式:

l 使用GROUP BY GROUPING SETS(a,b,c),则对(a),(b),(c)进行GROUP BY

l 使用GROUP BY GROUPING SETS((a,b),c), 则对(a,b),(c)进行GROUP BY

l GROUPING BY GROUPING SET(a,a) , 则对(a)进行2次GROUP BY, GROUPING SETS的参数允许重复

3.6 集合操作

? UNION、UNION ALL

用来获取两个或两个以上结果集的并集。

l UNION操作符会自动去掉合并后的重复记录

l UNION ALL返回两个结果集中的所有行,包括重复的行

l UNION操作符对查询结果排序,UNION ALL不排序

案例:合并职位是MANAGER的员工和薪水大于2500的员工合集,使用UNION

SELECT ename,job,sal FROM emp

WHERE job=‘MANAGER‘

UNION

SELECT ename,job,sal FROM emp

WHERE sal >2500;

技术分享

案例:使用UNION ALL实现上面案例

SELECT ename,job,sal FROM emp

WHERE job=‘MANAGER‘

UNION ALL

SELECT ename,job,sal FROM emp

WHERE sal >2500;

技术分享

? INTERSECT

INTERSECT函数获得两个结果集的交集,只有同时存在于两个结果集中的数据,才被显示输出。使用INTERSECT操作符后的结果集会以第一列的数据作升序排列。

案例:显示职位是MANAGER的员工和薪水大于2500的员工交集

SELECT ename,job,sal FROM emp

WHERE job=‘MANAGER‘

INTERSECT

SELECT ename,job,sal FROM emp

WHERE sal >2500;

技术分享

? MINUS

MINUS函数获取两个结果集的差集,只有在第一个结果集中存在,在第二个结果中不存在的数据,才能够被显示出来,也就是结果集1减去结果集2的结果。

案例:显示职位是MANAGER但薪水低于2500的员工记录

SELECT ename,job,sal FROM emp

WHERE job=‘MANAGER‘

MINUS

SELECT ename,job,sal FROM emp

WHERE sal >2500;

技术分享

SQL查询