|
我正在使用SQL Server 2008 R2。我有一个名为EmployeeHistory的表,具有以下结构和示例数据:
; ?4 T) G- v( b+ MEmployeeID Date DepartmentID SupervisorID
) f4 }- W. e) X# D7 X0 g10001 20130101 001 10009, Z+ c/ m/ f* \3 W% q0 M+ x' B
10001 20130909 001 100196 P) |; p2 l5 j/ |' D
10001 20131201 002 10018
1 |! {' X: n! X0 m10001 20140501 002 100175 I6 |, ~9 Z2 c
10001 20141001 001 10015( O( o# s& q* V7 V! n( n0 L
10001 20141201 001 10014
" n1 o+ l; Q$ o' R请注意,随着时间的推移,员工10001一直在更改2个部门和几个主管。我要做的是在“日期”字段中按顺序列出每个部门中该雇员的工作的开始和结束日期。因此,输出将如下所示:
! u( }- g4 h4 ~2 L3 OEmployeeID DateStart DateEnd DepartmentID 8 I8 S( t. l! u# [
10001 20130101 20131201 0013 i' E4 q! s4 F0 h; x7 U' X
10001 20131201 20141001 002
, j1 |2 w* a4 r10001 20141001 NULL 001
0 \1 y0 n: f% N我打算使用以下查询对数据进行分区,但失败了。部门从001更改为002,然后又更改为001。显然,我无法按DepartmentID进行分区…我敢肯定,我忽略了明显的部分。有什么帮助吗?先感谢您。
5 K5 G1 ~4 G& e: T0 e5 O0 N/ a, eSELECT * ,ROW_NUMBER() OVER (PARTITION BY EmployeeID, DepartmentID/ l1 `7 k& h7 f \+ v, K$ y
ORDER BY [Date]) RN FROM EmployeeHistory
% C: [ X1 D: e T " |& y0 s: q/ f: ~+ P
解决方案:
& p E4 ~5 u L$ Z4 N
& l% ^- ^. y; \+ h: m2 k+ d5 o" `$ K! v% K3 f
1 `) a% G: {6 r5 K. p 有点涉及。最简单的方法是参考我为您创建的SQL
/ |- O3 S* E0 P oFiddle,它产生确切的结果。您可以通过多种方法出于性能或其他方面的考虑对其进行改进,但是至少应该比某些替代方法更清楚一些。0 i3 C }3 E i+ D' m2 ?4 d
要点是,首先要获得数据的规范排名,然后使用该排名将数据划分为组,然后为每个组找到结束日期,然后消除任何中间行。ROW_NUMBER()和CROSS
5 t( B$ \3 A/ ]# W! {. pAPPLY在可读性方面有很大帮助。+ o! U/ s& S! h1 [
+ L' _, Q$ W. ]. z5 w
编辑2019:6 d/ c; u% V5 Q; j" P# w% P
实际上,由于某种原因,SQL Fiddle确实确实坏了,但是在SQL Fiddle站点上似乎是一个问题。这是一个完整的版本,刚刚在SQL Server0 [% D) v, s1 i4 N$ C
2016上进行了测试:
9 A! T( {- q% ^, I3 ECREATE TABLE Source4 h* z& W+ u2 F" x, d+ Y) a+ f
(
( i$ P9 b; W8 X, }8 J u# R EmployeeID int,' `- ?# ?# {/ @! u% m8 k; Z, r
DateStarted date,2 x0 w/ w( G& r
DepartmentID int
* w9 b; H/ }& r)% W! b0 b0 O$ f, [
INSERT INTO Source
* c2 f# W7 }. M9 [0 D7 FVALUES ], m }) y" ]
(10001,'2013-01-01',001),
, @& Z) _) ]$ i- E(10001,'2013-09-09',001),. z' ?- N$ i$ } u' h5 ~2 ~8 p
(10001,'2013-12-01',002),
% u% a+ P& k+ e5 W$ t( B* U(10001,'2014-05-01',002),
; i1 |' v; Y& y y5 h h# p(10001,'2014-10-01',001),
8 [; c: c) i6 Y- P3 d5 [(10001,'2014-12-01',001)
+ _: T- h; j; Q7 z \: `# z; X, i
5 u+ @5 A4 @) R3 g. H5 d5 m/ aSELECT *, $ B8 Z2 m3 `) N+ b `7 y6 c2 K. @$ a
ROW_NUMBER() OVER (PARTITION BY EmployeeID ORDER BY DateStarted) AS EntryRank,# a1 {7 p7 W D
newid() as GroupKey,& l# Y6 Y) D( F
CAST(NULL AS date) AS EndDate
3 z7 ]9 D. s# V$ Q( F+ f! f* p- CINTO #RankedData/ |) v% I* b8 {3 ^0 @0 B# L
FROM Source9 a9 T! p3 D3 G9 R4 j2 u" c6 b
;
# O; }* c' t6 d/ {* B" D! fUPDATE #RankedData
7 [! K" v. w `, a. U6 d" I: SSET GroupKey = beginDate.GroupKey( R: _: v* U, [2 } O
FROM #RankedData sup6 e3 s4 A O" G d" y, m
CROSS APPLY 0 ^: s: Q: |' S2 B
(
) h, J7 b( x1 v+ h0 t( K. Q SELECT TOP 1 GroupKey
" @) v$ Z. @/ k) _) q FROM #RankedData sub 3 R4 G, _ H( ]$ ?/ J- r
WHERE sub.EmployeeID = sup.EmployeeID AND6 V( B1 s$ D4 z. T( m' r8 G
sub.DepartmentID = sup.DepartmentID AND
* ^* x' K1 i# C NOT EXISTS ! V& J; ^) k2 I+ s4 i
(/ |2 C' u1 W0 D& X
SELECT * - O! a8 A* t: L1 w, F' q: s
FROM #RankedData bot ! `4 S+ a+ t8 W% z; R) W
WHERE bot.EmployeeID = sup.EmployeeID AND( r0 X6 \* X3 D) r; A; Y
bot.EntryRank BETWEEN sub.EntryRank AND sup.EntryRank AND
# ], [7 p. K9 l/ m, d bot.DepartmentID sup.DepartmentID6 w' i/ q) E6 K4 F4 z
)
+ K* |6 ^9 _1 Z) k4 D ORDER BY DateStarted ASC
" i& n/ _' W- E7 Q ) beginDate (GroupKey);' d( w$ _" b4 l- `
UPDATE #RankedData
# J; n" C+ \* M8 P! dSET EndDate = nextGroup.DateStarted z+ D6 x. T8 t+ Q4 ?" Q
FROM #RankedData sup% c8 i& p' a0 ?" ^1 I
CROSS APPLY 1 `, M, I1 U" H4 f' }% @) Z
( Y* k7 Y3 p5 s: q% p5 s9 e- o
SELECT TOP 1 DateStarted" y" P) E- U. ]: [ C, i2 B
FROM #RankedData sub
6 m |. t& x# S5 q8 P( S) L WHERE sub.EmployeeID = sup.EmployeeID AND7 y% C( Y2 I5 _8 c8 X) |2 r8 E% K* n
sub.DepartmentID sup.DepartmentID AND* m3 s4 }/ F0 R) j+ \. u7 T
sub.EntryRank > sup.EntryRank
- z: s+ S7 A9 Z4 T( A2 F* u3 m ORDER BY EntryRank ASC( g0 `( {- Q- V" M* x( f6 y3 x
) nextGroup (DateStarted);3 [& x7 j2 ~; ^' E5 V E" c& a% j; `
SELECT * FROM + N2 |! g" E7 S( `$ d6 A4 x
(
- k6 y6 ?7 B& n3 W! mSELECT *, ROW_NUMBER() OVER (PARTITION BY GroupKey ORDER BY EntryRank ASC) AS GroupRank FROM #RankedData
1 X- X" |4 r0 G. H6 V$ M) FinalRanking
) H: A. `$ r5 n% eWHERE GroupRank = 1
7 |: l% R5 b( zORDER BY EntryRank;8 j; Y- |, B& `3 t4 c5 }
DROP TABLE #RankedData
4 e4 T$ X5 j0 U9 J3 V! u" yDROP TABLE Source |
|