回答

收藏

ROW_NUMBER()OVER(PARTITION BY')使用麻烦

技术问答 技术问答 298 人阅读 | 0 人回复 | 2023-09-14

我正在使用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
分享到:
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则