oracle中复杂SQL语句——提升版
一、SQL语句的执行顺序
1、select 、 from 、where(group by、 having、 order by) 语句的执行顺序是什么呢?
select ——从纵向上进行过滤
from —— 一个表或多张表的连接
where —— 从横向上进行过滤
举个栗子:
“ select ID,Sname from student where score>=60;
– 从学生表中选择成绩大于等于60的学生的学号和姓名。
– 从某个表中在某个条件下选择某些列
2、完整的select语句呢?
同理 完整的是 from ->where-> group by -> having-> select ->order by
二、EXISTS的使用
exists用于判断查询所得的结果中是否有满足条件的记录存在。
“exists(xxx)”就表示括号里的语句能不能查出记录,它要查的记录是否存在。
举个栗子(巩固SQL执行顺序):
select * from student
where exists(select * from address where zz="兰州");
-- 如果exists中条件为真,那么就返回student表中所有的结果
-- 如果为假就什么也不返回
扩展:
①exist、 in 和 not exist的区别:
EXISTS:后面可以是整句的查询语句 如:SELECT * FROM titles
IN:后面只能是对单列 如: SELECT pub_id FROM titles
NOT EXISTS: 后面可以是整句的查询语句对EXISTS的否定。即就是不存在的返回真,存在的返回假。
② 有两个简单例子,以说明 “exists”和“in”的效率问题
1) select * from T1 where exists(select 1 from T2 where T1.a=T2.a) ;
T1数据量小而T2数据量非常大时,T1<<T2 时,1) 的查询效率高。
2) select * from T1 where T1.a in (select T2.a from T2) ;
T1数据量非常大而T2数据量小时,T1>>T2 时,2) 的查询效率高。
通过使用EXISTS,Oracle会首先检查主查询,然后运行子查询直到它找到第一个匹配项,这就节省了时间。Oracle在执行IN子查询时,首先执行子查询,并将获得的结果列表存放在一个加了索引的临时表中。在执行子查询之前,系统先将主查询挂起,待子查询执行完毕,存放在临时表中以后再执行主查询。这也就是使用EXISTS比使用IN通常查询速度快的原因。
三、复杂sql语句思维培养
1、如下两张表:
question:将住址在郑州的学生中学号最大的那一个学生的姓名取出来。
step 1: 主:在student表中选取一个姓名。从:家住郑州且学号最大
step 2: 确定两张表的连接条件 sno
select sname from student
where sno=(select max(sno) from address where zz='郑州');
- 聚合函数只能放在select后面
2、如下一张表:
question :找出姓名不唯一的学生的所有记录。
step1: select XM,count(*) from student group by XM;
step 2 : select XM from student group by XM having (count(*)>1);
step3 : select * from student where XM in (select XM from student group by XM having (count(*)>1) );
四、自连接的使用:
1、有如下一张表
question: 将这张表对应的管人人员编号替换成相应的管理人员姓名
step 1:select * from 管理人员 a ,管理人员 b;
– 即就是两张表的笛卡尔积
step 2:select * from 管理人员 a ,管理人员 b where a.管理人员编号=b.编号;
step 3:select a.编号 ,a. 姓名,b.姓名 as 管理人员姓名 from 管理人员 a ,管理人员 b where a.管理人员编号=b.编号;
select a.编号 ,a. 姓名,b.姓名 as 管理人员姓名
from 管理人员 a ,管理人员 b where a.管理人员编号=b.编号;
- as 可以用于取别名,也可省略不写 如:b.姓名 管理人员姓名
五、 select case when的用法
1、 判断条件在when中
select case
when substr('20180625',5,2) = '04' then '四月份'
when substr('20180625',5,2) = '05' then '五月份'
when substr('20180625',5,2) = '06' then '六月份'
when substr('20180625',5,2) = '07' then '七月份'
else null
end
from dual;
2、 case后有计算式
select case substr('20180625',5,2)
when '04' then '四月份'
when '05' then '五月份'
when '06' then '六月份'
when '07' then '七月份'
else null
end
from dual;
五、复杂更新语句的使用
1、有如下两张表:
question : 想在T1中”c”与表T2中”c”相同的情况下从表T2中将a,b覆盖表T1中的a,b怎么做 ?
step 1 :update t1 set a ,b
step 2 :update t1 set a ,b where t1.c in (select c from t2);
step 3 :update t1 set a= (select a from t2 where t1.c= t2.c ) , b =(select b from t2 where t1.c= t2.c) where t1.c in (select c from t2);
update t1
set a= (select a from t2 where t1.c= t2.c ) ,
b =(select b from t2 where t1.c= t2.c)
where t1.c in (select c from t2);
六、分析函数的使用
分析函数用于计算完成聚集的累计排名、序号等, 分析函数为每组记录返回多个行。
ROW_NUMBER ()over(条件)返回连续的排序,不论值是否相等
RANK()over(条件) 具有相等值的行排序相同,序数随后跳跃
DENSE_RANK ()over(条件)具有相等值的行排序相同,序号是连续的
举个栗子: 有一组成绩 90 80 70 70 60 60
使用row_number() 1 2 3 4 5 6
使用rank() 1 2 3 3 5 5
使用dense_rank() 1 2 3 3 4 4
七、decode中的if-then-else逻辑
在逻辑编程中,经常用到If – Then –Else 进行逻辑判断。在DECODE的语法中,实际上就是这样的逻辑处理过程。它的语法如下:
DECODE(value, if1, then1, if2,then2, if3,then3, … else )
Value 代表某个表的任何类型的任意列或一个通过计算所得的任何结果。当每个value值被测试,如果value的值为if1,Decode 函数的结果是then1;如果value等于if2,Decode函数结果是then2;等等。事实上,可以给出多个if/then 配对。如果value结果不等于给出的任何配对时,Decode 结果就返回else 。
* 需要注意的是,这里的if、then及else 都可以是函数或计算表达式。
1、有下面一张表:
question : 将student表中的sex列的1 2 1 转化为 男 女 男 的显示方式。
除此之外还可以使用:
Select name ,decode(sex, '1','男', '女') from student;
-- 此时的女相当于在else条件下的女
-- 用case实现:
select id,name,
case sex
when '1' then '男'
when '2' then '女'
end 性别
from student;
2、有如下一张表:
question : 返回当月销售数量最大的那个数
step 1 : sign()函数介绍,如果()中结果为正,返回1 ,如果()中结果为负,返回-1,如果()中结果为0,返回0
step 2 : select * from sales;
select month ,
decode(sign(SALES_TV- SALES_COMPUTER),
1,SALES_TV,
-1,SALES_COMPUTER,
0,SALES_TV)
from sales;
结果:
八、oracle中的行列转化
1、将表格式一显示成格式二:
select a.商品名称,
sum(decode(a.季度,'01', a.销售额 ,0 )) 一季度,
sum(decode(a.季度,'02', a.销售额 ,0 )) 二季度,
sum(decode(a.季度,'03', a.销售额 ,0 )) 三季度,
sum(decode(a.季度,'04', a.销售额 ,0 )) 四季度
from 销售 a
group by a.商品名称
order by 1;
- 说明 : 在a表中,先按商品名称进行分组,故sum函数中取到的01季度的只能是第一组电视机中的一季度的销售额。
九、rownum()的使用:
1、有如下一张表
- rownum() 只能与 < <= 以及特殊情况下的between and 连用。
- between 必须从1 开始!!
select * from yggz where rownum()<=3
select * from yggz where between 1 and 3;
question : 查找表中第3~5的记录并显示出来
-- 集合相减法
select * from yggz where rownum<=5
minus
select * from yggz where rownum<=2;
另一种方式: step 1:
--嵌套法
select bh,gz
from ( select yggz.*, rownum rn from yggz )
where rn >=3 and rn <= 5;
- 将rownum 作为一列 传入到表yggz中,然后在编辑条件rn >=3 and rn <= 5
十 、 删除重复记录
1、有如下一张表:
question:将其中的sno重复的行删除。
- rowid()rownum()均为伪列,实际上是存在在表中的,可以使用
- select student . *,rowid from student;查看到
- rowid() 里面的信息有 数据库对象号 数据文件号 数据块号 行号。
-- 删除学号有重复的 rowid不是最小的。
DELETE FROM student
WHERE sno IN
(SELECT sno FROM student GROUP BY sno HAVING COUNT(*) > 1)
AND ROWID NOT IN
(SELECT MIN(ROWID) FROM student GROUP BY sno
HAVING COUNT(*) > 1);
自连接删除法
-- A、B两表先进行内连接。
-- 取出内连接后两表中学号相等 且A.ROWID > B.ROWID的那些行的ROWID
-- 将rowid等于取出的这些ROWID中的行进行删除操作
DELETE FROM student WHERE ROWID IN
(SELECT A.ROWID FROM student A,student B
WHERE A.sno=B.sno AND A.ROWID > B.ROWID);
嵌套查询删除法
-- 我要删除一些记录
-- 删除条件是 rowid > 取出学号相等的那些行的rowid中的最小rowid
-- 换句话说就是在学号相等的条件下,rowid最小的是被保留的
DELETE FROM student d WHERE d.rowid >
(SELECT MIN(x.rowid) FROM student x WHERE d.sno=x.sno);
十一、group by grouping sets的使用
可以用GROUP BY GROUPING SETS来进行分组自定义汇总,可以应用它来指定你需要的总数组合。
其格式为: GROUP BY GROUPING SETS ((list), (list) … )
这里(list)是圆括号中的一个列序列,这个组合生成一个总数。要增加一个总和,必须增加一个(NULL)分组集。
GROUPING SETS 子句是 SELECT 语句的 GROUP BY 子句的扩展。通过 GROUPING SETS 子句,您可采用多种方式对结果分组,而不必使用多个 SELECT 语句来实现这一目的。这就意味着,能够减少响应时间并提高性能。
使用select语句进行多个分组:
SELECT NULL, NULL, NULL, COUNT( * ) AS Cnt
FROM Customers
WHERE State IN ( 'MB' , 'KS' )
UNION ALL
SELECT City, State, NULL, COUNT( * ) AS Cnt
FROM Customers
WHERE State IN ( 'MB' , 'KS' )
GROUP BY City, State
UNION ALL
SELECT NULL, NULL, CompanyName, COUNT( * ) AS Cnt
FROM Customers
WHERE State IN ( 'MB' , 'KS' )
GROUP BY CompanyName;
使用 GROUPING SETS 的多个分组:
SELECT City, State, CompanyName, COUNT( * ) AS Cnt
FROM Customers
WHERE State IN ( 'MB' , 'KS' )
GROUP BY GROUPING SETS( ( City, State ), ( CompanyName ) , ( ) );
上一篇: 京东购买意向预测