|
我正在使用SQL Server 2008 R2。我有一个名为EmployeeHistory的表,具有以下结构和示例数据:
2 a7 D9 O) j- O* _. zEmployeeID Date DepartmentID SupervisorID
/ [( v% e% y& X% F7 K; M0 c10001 20130101 001 10009
; t9 {5 l: u# n a0 Q10001 20130909 001 10019
* b+ ?2 e& `) ]% D9 E# e# `* C& `10001 20131201 002 10018
" n: G' }/ l, O9 C10001 20140501 002 10017+ ]8 l; p8 X, O) V
10001 20141001 001 10015
* m! b& F. r) j, I- ^( [10001 20141201 001 10014
/ s) Q3 x# a$ K2 l' }请注意,随着时间的推移,员工10001一直在更改2个部门和几个主管。我要做的是在“日期”字段中按顺序列出每个部门中该雇员的工作的开始和结束日期。因此,输出将如下所示:. r5 f4 T7 Q8 `* h1 F% t
EmployeeID DateStart DateEnd DepartmentID
- k+ F+ C; d# J' B D10001 20130101 20131201 001
( G2 m q! s" ^$ {7 q10001 20131201 20141001 002# V- r' O2 z$ C ~
10001 20141001 NULL 001
9 K; D' h, o6 Y8 A" c我打算使用以下查询对数据进行分区,但失败了。部门从001更改为002,然后又更改为001。显然,我无法按DepartmentID进行分区…我敢肯定,我忽略了明显的部分。有什么帮助吗?先感谢您。* d+ f0 p7 f% d3 F4 ?
SELECT * ,ROW_NUMBER() OVER (PARTITION BY EmployeeID, DepartmentID
, a7 V* H$ M. w8 p! @4 _ORDER BY [Date]) RN FROM EmployeeHistory' }, W$ ^. D) [3 O! M
% j. H7 j" u0 G$ U3 w7 l+ j/ D$ n( X解决方案:
+ M- h/ E# ]( r. j8 n * }" p! U0 s j1 D1 u- H
6 G5 r+ r' T3 s4 V
9 l [( S0 J3 K! n' O
有点涉及。最简单的方法是参考我为您创建的SQL
# `8 y7 x1 J4 A7 UFiddle,它产生确切的结果。您可以通过多种方法出于性能或其他方面的考虑对其进行改进,但是至少应该比某些替代方法更清楚一些。
! Y9 {- Z! D- \$ _要点是,首先要获得数据的规范排名,然后使用该排名将数据划分为组,然后为每个组找到结束日期,然后消除任何中间行。ROW_NUMBER()和CROSS+ ]0 @. v, h. U" C
APPLY在可读性方面有很大帮助。
9 V" u/ T* g+ [0 Z9 i# K0 D* j" } ~; P5 @# Y2 u4 k+ K
编辑2019:
4 L5 y: `* O' r% d# g* z9 d5 J& d实际上,由于某种原因,SQL Fiddle确实确实坏了,但是在SQL Fiddle站点上似乎是一个问题。这是一个完整的版本,刚刚在SQL Server! E7 s7 N. q: }, \# R- A6 }, J. K- W j
2016上进行了测试:- |- d+ P. a) {6 t# ^7 C
CREATE TABLE Source
: D0 L- [8 k* r3 f, ?(
4 c; E, C2 F3 r EmployeeID int,% o; n9 M, x& `5 I! |+ t( Z
DateStarted date,
3 Z x) k1 T) m) m+ k DepartmentID int8 ^! n8 H+ C8 L8 g& @6 ^( V3 k
)8 ~- v) r3 U0 `1 |5 E4 U( w
INSERT INTO Source# Y( x3 y( }! W S5 q1 H7 C
VALUES
: c% a5 j; z" h/ e3 `(10001,'2013-01-01',001),
7 i: \, _) I$ u5 y! \( e(10001,'2013-09-09',001),3 ]/ `0 y* h5 x: f1 |( }
(10001,'2013-12-01',002),
" G+ P! \3 a' V. V2 C(10001,'2014-05-01',002),* |7 E& q n$ o4 n* Z1 r, f- z* v
(10001,'2014-10-01',001),
2 U! g& ]1 w* b" x5 z(10001,'2014-12-01',001)5 R& n2 M4 ~" Q1 l1 m
! x) c8 c/ r/ v9 M, `) C. \SELECT *,
, w% G0 @" s7 ?: I- Q ROW_NUMBER() OVER (PARTITION BY EmployeeID ORDER BY DateStarted) AS EntryRank,
/ ~* h# n3 `4 G- _# ] newid() as GroupKey,6 h2 ? O. I4 _; a9 _- {+ I. S7 [
CAST(NULL AS date) AS EndDate! C! n5 H7 b3 m: O/ A- X" @" f0 Y! [0 W
INTO #RankedData& ]. m9 d; u; p
FROM Source! e7 D- g |# B2 f$ u |5 t# |0 `+ ?4 X
;( ^% ?1 W" I: c2 |+ i+ K, }
UPDATE #RankedData# R; U) B! ^4 D6 `1 f2 m
SET GroupKey = beginDate.GroupKey% q+ a# v t" E: V, G
FROM #RankedData sup$ J+ i! B) j4 c4 w1 ^5 q* D
CROSS APPLY
3 {& K( d2 T4 O# b* X' [ (
4 l' w* d2 \" H9 f" j SELECT TOP 1 GroupKey! Y0 A# X! N, y# n& C* I1 R- h
FROM #RankedData sub
: R. O+ B! |8 o" {) B+ R8 P WHERE sub.EmployeeID = sup.EmployeeID AND
, |- S" J* _8 {1 z0 Q sub.DepartmentID = sup.DepartmentID AND9 W! k8 W7 v' P, e% `6 x" h
NOT EXISTS
, s$ v" x# M8 l' Z5 h8 }7 F/ Y ($ e. x( a/ O$ O Z. l
SELECT * % v5 j; s6 R1 |6 V, u" L
FROM #RankedData bot
e2 Y! i2 w% I/ r WHERE bot.EmployeeID = sup.EmployeeID AND
9 v6 D! S$ W- U+ A' y3 m bot.EntryRank BETWEEN sub.EntryRank AND sup.EntryRank AND
2 M+ b! F4 N0 W) ^0 j! x bot.DepartmentID sup.DepartmentID4 m0 C0 L G. O, Y; l) ~
)
& d6 n" Z1 L7 X2 x! s% L ORDER BY DateStarted ASC5 O$ E! z/ }7 D
) beginDate (GroupKey);
7 D- `4 d) h+ C ^5 |0 ~8 j* uUPDATE #RankedData
% l% X; S U! @$ G; wSET EndDate = nextGroup.DateStarted" }7 x. S0 F3 f8 A! g. H) H$ v$ n! q
FROM #RankedData sup
! }9 {1 c, X" [7 y CROSS APPLY
8 T0 _$ o) I( j# d6 X! K; h () y7 l! T5 a, c2 k
SELECT TOP 1 DateStarted2 w7 U- z% B) ]9 I
FROM #RankedData sub6 ^( u+ W/ ?! A- q% J ~5 n) q
WHERE sub.EmployeeID = sup.EmployeeID AND
$ e# G& G6 ]8 U G9 l D sub.DepartmentID sup.DepartmentID AND
2 Q$ m& S* f$ v j) G4 G) L4 u sub.EntryRank > sup.EntryRank
3 d% d* @5 ]+ J ORDER BY EntryRank ASC
8 D3 q( E( J1 o! `2 m! u0 l ) nextGroup (DateStarted);# J1 ]) H! v7 |
SELECT * FROM
/ ]* A4 F: k: t* ]7 Y0 F8 _(
, } c' ^4 _% y1 J; JSELECT *, ROW_NUMBER() OVER (PARTITION BY GroupKey ORDER BY EntryRank ASC) AS GroupRank FROM #RankedData% c( s4 a$ U1 F9 X* |0 U" M
) FinalRanking
9 J. O! z$ \* F4 S7 |WHERE GroupRank = 12 z: v6 a8 c! s8 V/ M
ORDER BY EntryRank;$ s/ u8 I3 i' g6 b
DROP TABLE #RankedData5 D% A8 D0 ^5 k' x" t' C2 O+ C
DROP TABLE Source |
|