SQLServer复杂SQL逻辑实现
2015-07-21 10:03
309 查看
转载请注明出处:http://blog.csdn.net/danielinbiti/article/details/46948421
一、问题
如下图,已有表a与表b的数据,如何通过SQL语句变成表c?表a是UserName相同时,根据Month降序汇总Salary数据;表b是UserName对应SumSalary的上限值;表c是从表a中取出表b上限值以下的分录,若分录的SumSalary值大于b表的Salary,则拆分出刚好汇总等于b表的Salary数。
表A的SQL语句:
[sql]
view plaincopy
create table b(
UserName nvarchar(200),Salary int
)
create table User_Salary (UserName nvarchar(200), Month nvarchar(20), Salary int)
go
insert into User_Salary (UserName,Month,Salary ) values('AAA','2010/12',1000)
insert into User_Salary (UserName,Month,Salary ) values('AAA','2011/01',2000)
insert into User_Salary (UserName,Month,Salary ) values('AAA','2011/02',3000)
insert into User_Salary (UserName,Month,Salary ) values('BBB','2010/12',2000)
insert into User_Salary (UserName,Month,Salary ) values('BBB','2011/01',2500)
insert into User_Salary (UserName,Month,Salary ) values('BBB','2011/02',2500)
insert into User_Salary (UserName,Month,Salary ) values('CCC','2013/12',5000)
insert into User_Salary (UserName,Month,Salary ) values('CCC','2013/04',4000)
insert into User_Salary (UserName,Month,Salary ) values('CCC','2013/02',3000)
二、SQL
SQLServer:
[sql]
view plaincopy
SELECT username,MONTH,Salary2 salary,SumSalary2 sumsalary FROM (
SELECT k.*,case when b.flag1=0 then -1 else b.flag1 end flag2
,case when B.flag1=1 and k.flag1<>1 then k.salary-(k.SumSalary-k.maxSalary) else k.salary end Salary2
,case when B.flag1=1 and k.flag1<>1 then k.maxSalary else k.SumSalary end SumSalary2 FROM
(SELECT A.*,row_number() OVER(order by UserName,month desc) r FROM
(SELECT a.*,case when maxSalary>SumSalary then 1 when maxSalary=SumSalary then 0 else -1 end flag1 from(
select u.*
,(select SUM(salary) from User_Salary where User_Salary.Month>=u.month and User_Salary.UserName = u.userName) as SumSalary
,(select Salary from b where b.UserName = u.UserName) as maxSalary
from User_Salary u
) a )A
) k
LEFT JOIN
(SELECT A.*,row_number() OVER(order by UserName,month desc) r FROM
(SELECT a.*,case when maxSalary>SumSalary then 1 when maxSalary=SumSalary then 0 else -1 end flag1 from (
select u.*
,(select SUM(salary) from User_Salary where User_Salary.Month>=u.month and User_Salary.UserName = u.userName) as SumSalary
,(select Salary from b where b.UserName = u.UserName) as maxSalary
from User_Salary u
) a )A
) B
on k.R = B.R+1
) a WHERE FLAG1=1 OR FLAG1 = 0 OR FLAG2 = 1
三、总结
主要还是对上一行下一行记录的获取上,也就是以前写的SQLServer的lead,lag的实现。如果SQLServer2010(好像是这版本),就有内置的lead,lag了,sql就简单了。
个人觉得这类SQL当做练手是不错的,但用着应用中复杂度就有点高了,应对对应用的业务和表结构做重新处理。
一、问题
如下图,已有表a与表b的数据,如何通过SQL语句变成表c?表a是UserName相同时,根据Month降序汇总Salary数据;表b是UserName对应SumSalary的上限值;表c是从表a中取出表b上限值以下的分录,若分录的SumSalary值大于b表的Salary,则拆分出刚好汇总等于b表的Salary数。
表A的SQL语句:
[sql]
view plaincopy
create table b(
UserName nvarchar(200),Salary int
)
create table User_Salary (UserName nvarchar(200), Month nvarchar(20), Salary int)
go
insert into User_Salary (UserName,Month,Salary ) values('AAA','2010/12',1000)
insert into User_Salary (UserName,Month,Salary ) values('AAA','2011/01',2000)
insert into User_Salary (UserName,Month,Salary ) values('AAA','2011/02',3000)
insert into User_Salary (UserName,Month,Salary ) values('BBB','2010/12',2000)
insert into User_Salary (UserName,Month,Salary ) values('BBB','2011/01',2500)
insert into User_Salary (UserName,Month,Salary ) values('BBB','2011/02',2500)
insert into User_Salary (UserName,Month,Salary ) values('CCC','2013/12',5000)
insert into User_Salary (UserName,Month,Salary ) values('CCC','2013/04',4000)
insert into User_Salary (UserName,Month,Salary ) values('CCC','2013/02',3000)
二、SQL
SQLServer:
[sql]
view plaincopy
SELECT username,MONTH,Salary2 salary,SumSalary2 sumsalary FROM (
SELECT k.*,case when b.flag1=0 then -1 else b.flag1 end flag2
,case when B.flag1=1 and k.flag1<>1 then k.salary-(k.SumSalary-k.maxSalary) else k.salary end Salary2
,case when B.flag1=1 and k.flag1<>1 then k.maxSalary else k.SumSalary end SumSalary2 FROM
(SELECT A.*,row_number() OVER(order by UserName,month desc) r FROM
(SELECT a.*,case when maxSalary>SumSalary then 1 when maxSalary=SumSalary then 0 else -1 end flag1 from(
select u.*
,(select SUM(salary) from User_Salary where User_Salary.Month>=u.month and User_Salary.UserName = u.userName) as SumSalary
,(select Salary from b where b.UserName = u.UserName) as maxSalary
from User_Salary u
) a )A
) k
LEFT JOIN
(SELECT A.*,row_number() OVER(order by UserName,month desc) r FROM
(SELECT a.*,case when maxSalary>SumSalary then 1 when maxSalary=SumSalary then 0 else -1 end flag1 from (
select u.*
,(select SUM(salary) from User_Salary where User_Salary.Month>=u.month and User_Salary.UserName = u.userName) as SumSalary
,(select Salary from b where b.UserName = u.UserName) as maxSalary
from User_Salary u
) a )A
) B
on k.R = B.R+1
) a WHERE FLAG1=1 OR FLAG1 = 0 OR FLAG2 = 1
三、总结
主要还是对上一行下一行记录的获取上,也就是以前写的SQLServer的lead,lag的实现。如果SQLServer2010(好像是这版本),就有内置的lead,lag了,sql就简单了。
个人觉得这类SQL当做练手是不错的,但用着应用中复杂度就有点高了,应对对应用的业务和表结构做重新处理。
相关文章推荐
- sql developer执行sql文件
- 数据库分库分表方案
- Quartz作业调度定时完成数据库操作
- 【mysql】如何做到表内存在同名字段就更改记录,不存在就新增记录(replace的详细使用)
- 单机oracle数据库打最新11.2.0.4.7记录
- 如何在SQL Server 2014中用资源调控器压制你的存储?
- 重置SQLSERVER表的自增列,让自增列重新计数
- SQL Server Profiler工具
- com.mysql.jdbc.exceptions.jdbc4.CommunicationsException: Communications link failure 解决办法
- com.mysql.jdbc.exceptions.jdbc4.CommunicationsException: Communications link failure 解决办法
- JSP连接sqlserver 2008遇到的一些问题
- ubuntu MySQL采用apt-get install安装目录
- 群雄逐鹿 共话新型数据库
- mysql max_allowed_packet查询和修改
- mysql格式时间戳
- Oracle Merge Into 用法详解
- nginx+tomcat7+memcache集群,使用memcached-session-manager实现session共享方案
- 使用缓存Memcache存储更新微信access token
- mysql查询一天,查询一周,查询一个月的数据
- 使用 SQL SERVER PROFILER 监测死锁