当我们拿到题目的时候,并不是急于作答,那样会得不偿失的,而是分析思路,采用什么方法,达到什么目的,还要思考有没有简单的方法或者通用的方法等等,这样才会达到以一当十的效果,这样的惯性思维其实早在我们度高中的时候就被领教了,所谓“万变不离其宗”吧。以下各题来自日常所见,或QQ群,或面试题,或博客园。
题目一:如下表所示,现需要按照收款员统计收款和退款合计金额。
实现结果需如下显示:
分析:想要的结果(记为表B)和源数据(记为表A)相比,有共同的列(收款员),不同的是表A的金额根据标记和收款员分成了两列,所以这个需求可以用语言表述一下:首先根据收款员分组(group by),然后当标记为“收”时,金额计入收款合计(sum);当标记为“退”时,金额计入退款合计(sum)。当……时……,这不就是SQL的条件判断嘛?盘点SQL的条件语句不多,if……else……和case……when……then……else……end。这样问题就迎刃而解了。
解决方案如下:
1
2
3
4
5
6
7
8
9
10
11
12
|
with ta as ( select '收' as 标记, '100' as 收款员,150 as 金额 union select '收' , '100' ,375 union select '退' , '100' ,78 union select '收' , '200' ,74 ) select 收款员, sum ( case when 标记= '收' then 金额 else 0 end ) as 收款合计, sum ( case when 标记= '退' then 金额 else 0 end ) as 退款合计 from ta group by 收款员 |
题目二:如下表A(左边)职员信息表,其中ID为职员工号,name为职员姓名;表B(右边)为职员任务分配表,其中ID为职员工号(和表A中ID对应),Task为任务编号。
现需求每个职员的任务数。结果如下显示:
其实原题是这样的:只有一张表B,求求每个职员的任务数。没有找到比较好的方法实现,不做讨论,欢迎高人指点。
分析:此题的难点在于表B中的ID复杂表示,其实这样有悖于数据库的设计原则,理应表A和表B的ID一一对应。既然是题,我们只能从当前的条件入手了,攻破难点的关键在于判断A中ID在B中ID出现与否,如果出现那么如何统计出现的次数。判断出现与否需要用到函数CHARINDEX。
解决方案如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
|
--创建测试数据 WITH TA AS ( SELECT '1,2' AS ID, 'job1' AS task UNION SELECT '1,2,3' , 'job3' UNION SELECT '2,3' , 'job2' UNION SELECT '3,4,5' , 'job4' ) ,TB AS ( SELECT '1' AS ID, '张三' as name UNION SELECT '2' , '王二' UNION SELECT '3' , '李四' UNION SELECT '4' , '李明' UNION SELECT '5' , '王五' ) SELECT B.ID,B. name , COUNT (1) AS TASKS FROM TA A,TB B WHERE CHARINDEX(B.ID,A.ID)>0 GROUP BY B.ID,B. name order by B.ID |
题目三:原题参见这篇文章:http://www.zzvips.com/article/57305.html
如下表City所示,code为行政区域码(六位数字,前两代表省级,中间两位代表市级,最后两位代表县级,不考虑xx00xx情况),city为城市名称,CCode为该城市所属的省级或者市级行政区域码。
现需求如下结果:
分析:分析表city,code的含义十分明显,所需要的结果也很明显,如果是省就是显示省份;是市则显示为所属省级+市级;是县级则显示为所属省级+所属市级+县级。貌似可以用题目一分析中提到的SQL条件语句实现,但是转念一想,还是有差别,这里需要先判断city属于省级?市级?县级?然后在对应起来的,这样还得有参照表,复杂了。回到结果表中来进行分析,其实判定city属于省市县的问题并不难,code的含义已经说明了,只要转换表述:在表City中,当code的后四位为“0000”时,肯定是省级;当code的后两位为“00”,并且后四位不为“0000”时,肯定是市级;当code后两位不为“00”时,为县级。这样省市县的判定就一目了然了,然后,根据市级编码追朔所属的省级,并得出所属省级+市级,县级追朔所属的市级,得出所属省级+所属市级+所属县级,通过运用这种简单的递归思想,解决方案便跃然纸上了。
解决方案如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
|
--测试数据 with ta as ( select '110000' as code, '北京市' city, '110000' Ccode union select N '110200' , N '西城区' , N '110200' union select N '110300' , N '崇文区' , N '110300' union select N '430000' , N '湖南省' , N '430000' union select N '430100' , N '长沙市' , N '430100' union select N '430101' , N '望城县' , N '430100' ) select * into City from ta select * from City; --解决方案 with ta as ( --省级 select code,city,Ccode,city content from City where right (code,4)= '0000' ), tb as ( --市级 select b.code,b.city,b.Ccode,a.city+ ',' +b.city as content from ta a,City b where left (a.Ccode,2)= left (b.Ccode,2) and right (b.code,2)= '00' and right (b.code,4)<> '0000' ), tc as ( select c.code,c.city,c.Ccode,b.content+ ',' +c.city content from tb b,City c where left (b.Ccode,4)= left (c.Ccode,4) and right (c.code,2)<> '00' ) select * from ta union select * from tb union select * from tc |
通过上述几道小题,常思常新,温故了SQL的部分知识,当然方法很多,变式很多,如题目二统计表B中每个Task的人数等。不足之处,欢迎各位指点!