巧用SQL進(jìn)行數(shù)據(jù)累加
比如有這樣一個需求,一張表格(User_Salary)包含每個人(UserName)每個月份(Month)發(fā)的薪水(Salary)
求這樣一個結(jié)果集:每個人每月所發(fā)薪水及累計所得薪水和,如下表
UserName | Month | Salary |
AAA | 2010/12 | 1000 |
AAA | 2011/01 | 2000 |
AAA | 2011/02 | 3000 |
BBB | 2010/12 | 2000 |
BBB | 2011/01 | 2500 |
BBB | 2011/02 | 2500 |
結(jié)果
UserName | Month | Salary | Cumulation |
AAA | 2010/12 | 1000 | 1000 |
AAA | 2011/01 | 2000 | 3000 |
AAA | 2011/02 | 3000 | 6000 |
BBB | 2010/12 | 2000 | 2000 |
BBB | 2011/01 | 2500 | 4500 |
BBB | 2011/02 | 2500 | 7000 |
當(dāng)然這個結(jié)果在Excel中十分好實(shí)現(xiàn),只需要一個公式就好:
注意G2的公式一定要保持***個列不動所以就是$F$2:F2,然后向下拖一下就可以,但是,這只適用于數(shù)據(jù)固定的情況下,試想,如果有100個員工的數(shù)據(jù),豈不是要拖100下。當(dāng)然也可能有其他辦法,這個我就不知道了。
下面,如果用sql實(shí)現(xiàn)能有什么辦法呢?首先想到的是游標(biāo)。
對游標(biāo)的確可以實(shí)現(xiàn),寫程序也可以實(shí)現(xiàn),因?yàn)樗麄兊乃枷胧且粯拥模号袛嘁幌旅质遣皇且呀?jīng)遍歷過了,如果遍歷過了,就累加一下,如果沒有就從0加起。這樣很好理解,但是寫的很費(fèi)時,其實(shí)一條sql語句就可以實(shí)現(xiàn)的,那就是子查詢。
- 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)
- go
- select UserName,Month,Salary,
- Cummulation=(
- select SUM(Salary)
- from
- User_Salary i
- where
- i.UserName=o.UserName and i.Month<=o.Month
- )
- from User_Salary o
- order by 1,2
- go
- drop table User_Salary
大家知道SQL查詢的結(jié)果是面向集合,而這種嵌套的子查詢恰恰就是在整個結(jié)果集返回之前做的對于每一行的運(yùn)算。也許這樣的寫法不是很容易理解,那么下面這個寫法應(yīng)該容易理解多了。
- 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)
- go
- select
- A.UserName,A.Month,MAX(A.Salary) as Salary,SUM (B.Salary) as Accumulation
- from
- User_Salary A inner join User_Salary B
- ON
- A.UserName = B.UserName
- where
- B.Month <= A.Month
- group by
- A.UserName,A.Month
- order by
- A.UserName,A.Month
- go
- drop table User_Salary
這樣用聯(lián)合的方式就好理解一些,其實(shí)這樣就是把每一行對應(yīng)比他月份小的值分成一組,然后進(jìn)行運(yùn)算,如果這樣不明白,那么下面的sql會使這個查詢更加好理解:
- select
- A.*,B.*
- from
- User_Salary A inner join User_Salary B
- ON
- A.UserName = B.UserName
- where
- B.Month <= A.Month
- order by 1,2
這樣的結(jié)果就顯而易見了
這就是子查詢相關(guān)的遞歸(可以這么說?)算法。
子查詢執(zhí)行計劃
join執(zhí)行計劃
通過上述2個執(zhí)行計劃,雖然執(zhí)行計劃不同,但大體一致,這其中的區(qū)別我就不太明白了(不知道是先排序再join好 還是先join在排序好,但是我個人覺得第二種比較容易理解.).
原文出處:http://www.cnblogs.com/mylhei/archive/2011/03/09/1978184.html
【編輯推薦】