|
我正在使用SQL Server 2008 R2。我有一个名为EmployeeHistory的表,具有以下结构和示例数据:
8 C3 G+ U! |9 WEmployeeID Date DepartmentID SupervisorID' Q, x. i; L2 o8 [6 ]* a
10001 20130101 001 10009$ r, H) S- Q' P( V6 J0 d
10001 20130909 001 10019
. |3 N0 `# q" D! _7 V0 ?0 Y; z2 C10001 20131201 002 10018; \$ g' D' N7 \% p9 B1 u ~
10001 20140501 002 10017+ v5 g; a6 Y# l
10001 20141001 001 10015
2 M. o j6 J* \6 |1 L( I$ Q: ^10001 20141201 001 10014
2 h& |; ^! n( w- s- y/ ~# r请注意,随着时间的推移,员工10001一直在更改2个部门和几个主管。我要做的是在“日期”字段中按顺序列出每个部门中该雇员的工作的开始和结束日期。因此,输出将如下所示:" W$ i; {' o, ~! U) s9 ]
EmployeeID DateStart DateEnd DepartmentID
& Z( m: Z# u, ~$ y" L2 }10001 20130101 20131201 001
$ a. x) C: u p$ t: J10001 20131201 20141001 002
5 v! V! }! ]( \! M+ M10001 20141001 NULL 001
* I8 b+ ~6 w" u" z) G5 y4 e) N我打算使用以下查询对数据进行分区,但失败了。部门从001更改为002,然后又更改为001。显然,我无法按DepartmentID进行分区…我敢肯定,我忽略了明显的部分。有什么帮助吗?先感谢您。( s# x! X; D3 [( C9 _
SELECT * ,ROW_NUMBER() OVER (PARTITION BY EmployeeID, DepartmentID& D* O4 A- N4 y
ORDER BY [Date]) RN FROM EmployeeHistory/ [4 R8 q' c3 k; `
6 a& T6 q6 m; f, q5 Q. @* y" W6 d解决方案:
$ z' A/ X0 J6 C/ g/ [
& F$ x9 z" ]7 v+ b4 \, ~ `& V: T9 s8 {7 {" h& K/ {
# W# `# w) ^& G3 V- q
有点涉及。最简单的方法是参考我为您创建的SQL
) s- n0 `+ Z/ f% U1 ?Fiddle,它产生确切的结果。您可以通过多种方法出于性能或其他方面的考虑对其进行改进,但是至少应该比某些替代方法更清楚一些。
' J/ g2 W7 P# G( l5 T: W: i1 z& Q6 p要点是,首先要获得数据的规范排名,然后使用该排名将数据划分为组,然后为每个组找到结束日期,然后消除任何中间行。ROW_NUMBER()和CROSS
; A- }- K M' H- Y$ l( EAPPLY在可读性方面有很大帮助。+ Q: I) E3 M# s
9 |8 _6 {2 L0 q7 X5 Z
编辑2019:
2 \2 P* M7 Y6 G( l' t实际上,由于某种原因,SQL Fiddle确实确实坏了,但是在SQL Fiddle站点上似乎是一个问题。这是一个完整的版本,刚刚在SQL Server
; _9 v7 K2 ~, u, A5 X2016上进行了测试:
$ f. I* ~3 d7 [/ ^0 g9 A- rCREATE TABLE Source
% R+ f( Y- H, U+ I* ~(
D2 i" [+ E4 X* ^ EmployeeID int,
4 m' `8 ~7 Q( f; G5 B DateStarted date,
`# K9 A5 |# ]) y+ p DepartmentID int# V: M: g6 q0 @
)
% X4 j2 M0 u6 Y# ]. L% zINSERT INTO Source
; }: Q* ]' a7 s# H+ a8 r. T, }7 rVALUES7 M$ \: U7 b1 z3 q
(10001,'2013-01-01',001),- @3 b/ }5 J8 V& y
(10001,'2013-09-09',001),
( k$ K ~# I5 K3 ]9 s/ d0 e3 {(10001,'2013-12-01',002),( M' Q1 A) x4 }' [. c% N+ n
(10001,'2014-05-01',002),
/ F& B$ V# x! X7 Y/ g(10001,'2014-10-01',001),
! k$ f' w# P' K/ g( D# t(10001,'2014-12-01',001)
$ }. F Z3 W" v* S- W! J1 w' Y+ z' ]% R( G
SELECT *,
1 a( G4 q; g1 @9 _+ Y+ Q4 m. ]2 H ROW_NUMBER() OVER (PARTITION BY EmployeeID ORDER BY DateStarted) AS EntryRank,
' y; v4 {8 M$ t) o( I% c8 k, r newid() as GroupKey,
' C6 ^* Z7 Z. ~! \7 Y4 F: X% f$ W CAST(NULL AS date) AS EndDate
2 U( m* P# e, o* jINTO #RankedData
# P' z5 E4 S8 K2 k: i* B4 AFROM Source
+ n" \& @9 Z- J8 d7 b& K: |+ x5 S;! t% z! o4 l2 n) k ~
UPDATE #RankedData4 y+ U7 ~: H, p9 Z' H- ?' f
SET GroupKey = beginDate.GroupKey# R) Y, e: f! ~ D* U& S
FROM #RankedData sup
+ @. u- z$ x1 ]7 D CROSS APPLY : U* C- k2 ~( n0 q; P) c- R0 N; q
(
' j7 ]. V( V$ l8 G SELECT TOP 1 GroupKey
2 @. U' W! _3 V4 o k FROM #RankedData sub 0 ~! {" v# ] p& H# Y
WHERE sub.EmployeeID = sup.EmployeeID AND J! `4 U) \; t
sub.DepartmentID = sup.DepartmentID AND) `& t+ `6 I) `7 U9 I3 @; F
NOT EXISTS
/ F& o$ t \5 J1 m (6 _# v8 v5 U# ?4 T6 m
SELECT *
! g# f( Y7 C$ Z7 _- P4 c0 t- A FROM #RankedData bot
: N) k# P; c" Y' s WHERE bot.EmployeeID = sup.EmployeeID AND
* ]( x! T7 ]# t* w0 K; g( k bot.EntryRank BETWEEN sub.EntryRank AND sup.EntryRank AND8 K$ K, u. x) D0 t
bot.DepartmentID sup.DepartmentID
9 G" Q) _$ P* E2 p- I3 p4 D )
! b; U5 B; L1 { ORDER BY DateStarted ASC4 R3 l6 v( t. i! g) v4 q
) beginDate (GroupKey);: E9 V7 `. P2 j3 Y
UPDATE #RankedData
1 s: z' Q8 W( `; E# a5 o5 I6 oSET EndDate = nextGroup.DateStarted
/ j& A4 _( S: p- tFROM #RankedData sup2 i: t& }3 c% L1 U+ D
CROSS APPLY
$ `) J4 V* {, b. d& B3 R, ^ (
, u3 q/ o/ O5 l2 |2 S3 ^) K SELECT TOP 1 DateStarted
' l, g6 [4 o0 K+ w+ @ FROM #RankedData sub
& M) x3 A% R% i0 f/ h WHERE sub.EmployeeID = sup.EmployeeID AND9 G! ?1 _3 A- Q3 G# F" ]6 E+ ]
sub.DepartmentID sup.DepartmentID AND
# r! H* M. f$ ?* `7 |5 |- N, d sub.EntryRank > sup.EntryRank
+ u; K' s& @- W ORDER BY EntryRank ASC
+ {* A5 w6 @* {0 K" m p6 A) p ) nextGroup (DateStarted);! [6 Q5 v/ n! R; E2 E
SELECT * FROM $ u0 T/ L* X4 g& |
() e, d3 a# {* V2 c( d0 v9 W- `: q
SELECT *, ROW_NUMBER() OVER (PARTITION BY GroupKey ORDER BY EntryRank ASC) AS GroupRank FROM #RankedData$ e+ s3 }4 `& y. m) N- S
) FinalRanking7 {; h0 H: ^# H% r
WHERE GroupRank = 1
8 k1 @ I& c# z7 ~# J* G6 Q4 wORDER BY EntryRank;
+ F3 u& l% L/ M7 m1 XDROP TABLE #RankedData- c6 Y5 [+ Q7 K. S
DROP TABLE Source |
|