有趣的SQL,有趣的函数

 

有见csdn里一个很有趣的题,

 

有一个表,结构如下: 
编号,姓名,时间,基本工资,奖金,扣款 
1    张三  8-20    1000    1000  5 
2    李四  8-20    1100    900    10 
3    张三  9-20    900    1000  10 
4    李四  9-20    1100    900    13 
5    王五  9-20    900    100    0 


如果我对8-20  和  9-20  的基本工资做异动数据查询 我要求得到这样的一个临时数据视图 

编号,姓名,基本工资  备注 
1    张三  -100    
2    王五  900        新增 

 

原帖在http://topic.csdn.net/u/20090830/20/4f135d40-a52d-4346-ac15-599b2951af39.html?seed=709316630&r=59447116#r_59447116

 

 

遇到有趣的题,当然激发我的兴趣哟,一看这样需要上下记录对照的,就想到lag和lead函数了

 

这里也借这个题,好好的解释一下lag和lead的用法

 

Lag 取前面n条的记录

lag(field, n, defaultv)

 

Lead取后面那条的记录

lead(field, n, defaultv)

 

field是取值的字段, n是前后几条, defualtv是默认值,类似nvl(lag(field, n), defaultv)

 

lag和lead必须和开窗函数over一起来使用,

 

结合着这个题目,如何使用lag/lead和over来使用了,实战甚于一切

 

先做数据

现在习惯用with as来做数据了

 

with temp as

(select '张三' name, '8-20' date1,  1000 a1,   1000 a2,  5 a3 from dual

union all

select '李四' name, '8-20' date1,  1100 a1,    900  a2,  10 a3 from dual

union all

select '张三' name, '9-20' date1,  900 a1,    1000  a2,  10 a3 from dual

union all

select '李四' name, '9-20' date1,  1100 a1,    900  a2,  13 a3 from dual

union all

select '王五' name, '9-20' date1,  900 a1,    100  a2,  0 a3 from dual)

 

 

数据如下,建立临时的视图。

 

下面是步骤,这里需要前后记录做比对,从而算出异动值,同时有可能只有一条记录的,时间后-时间前,所以用date1排序desc,

以user为单位,所以需要按name来partition

如下

select name,a1,date1,  a1-(lead(a1, 1, 0) over(partition by name order by date1 desc)) c from temp;

 

 

NAME         A1 DATE          C

---- ---------- ---- ---------- --

李四       1100 9-20          0

李四       1100 8-20       1100

王五        900 9-20        900

张三        900 9-20       -100

张三       1000 8-20       1000

 

 

结果如下,现在异动数据出来了,但是,多余的记录要去掉,怎么去掉多余的记录了。

 

其实这里两天记录我们只用第一条就可以了。row_number就可以搞定哟。

继续

select name,a1,date1,  a1-(lead(a1, 1, 0) over(partition by name order by date1 desc)) c, row_number() over(partition by name order by date1 desc) rn from temp

 

 

NAME         A1 DATE          C         RN

---- ---------- ---- ---------- ---------- --

李四       1100 9-20          0          1

李四       1100 8-20       1100          2

王五        900 9-20        900          1

张三        900 9-20       -100          1

张三       1000 8-20       1000          2

 

 

用rn和c=0过滤就可以了,变化为

select name "姓名", c "基本工资" from (

select name,a1,date1,  a1-(lead(a1, 1, 0) over(partition by name order by date1 desc)) c, row_number() over(partition by name order by date1 desc) rn from temp) where rn = 1 and c <>0

 

 

姓名   基本工资

---- ----------

王五        900

张三       -100

 

 

下面该处理备注了,备注的应该是只有一条记录的,用sum或者count就可以了

sum(1) over(partition by name) 这里要特别注意 开窗函数的range的问题。不能用order by在over里,否则默认的开窗的range不是full range,而是current position。

 

sum(1) over(partition by name order by date1)

差别

 

NAME         A1 DATE          C         RN        CNT

---- ---------- ---- ---------- ---------- ----------

李四       1100 9-20          0          1          1

李四       1100 8-20       1100          2          2

王五        900 9-20        900          1          1

张三        900 9-20       -100          1          1

张三       1000 8-20       1000          2          2

 

 

sum(1) over(partition by name)

 

NAME         A1 DATE          C         RN        CNT

---- ---------- ---- ---------- ---------- ----------

李四       1100 9-20          0          1          2

李四       1100 8-20       1100          2          2

王五        900 9-20        900          1          1

张三        900 9-20       -100          1          2

张三       1000 8-20       1000          2          2

 

 

主要是cnt的差别,这是over开窗的一个特性,很多不熟悉的朋友经常这里不知何为了。

去掉order by使用full range

 

最后的效果如下

select name "姓名", c "基本工资", decode(cnt, 1, '新增', '') "备注" from (select name,a1,date1,  a1-(lead(a1, 1, 0) over(partition by name order by date1 desc)) c, row_number() over(partition by name order by date1 desc) rn, sum(1) over(partition by name) cnt from temp) where rn = 1 and c<>0;

 

 

姓名   基本工资 备注

---- ---------- ----

王五        900 新增

张三       -100

 

 

 

这里的题很有趣,也带出了lag lead over这样功能强大的函数。

 

这里还合理的利用了over的range特性,啊,做这样的题,自己也受益不浅哟,快哉,快哉。




 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

inthirties

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值