回答

收藏

查找SQL中连续递增数字的最长序列

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

对于这个例子说,我有两个字段的表,AREA varchar(30)和OrderNumber INT。
* M- k. p8 S& o1 _" h6 q该表具有以下数据, V! t" p( ]3 w' e# y4 a
AREA      | OrderNumber" S; R* S  m% l* e0 e  r
Fontana   |       326 [) {1 S* D+ Q
Fontana   |       428 [; u  r! V6 v' m; l- D
Fontana   |       76
5 r6 U- g* v+ h) n2 g* a" {% sFontana   |       12
+ p" a' g) b6 `4 r6 wFontana   |        3# B/ x7 N6 w+ L6 l
Fontana   |       99  e4 u: ~6 f0 _* p: ?1 M
RC        |       32  v7 W' @& R4 x4 Q" E3 B6 M
RC        |        1
2 b& R0 M. m0 {. X& v  S! K$ hRC        |        8
& A7 N6 p$ u- t- T; s, DRC        |        98 r2 a* V& h6 ~" V
RC        |        4
3 b( Q+ J9 ]2 z) c# w) \我想回来
: l8 J$ v& i. F5 F$ B我想返回的结果是每个区域递增连续值的最长长度。对于Fontana it is 3 (32, 42, 76)。For RC it is 2 (8,9)
( q# ?" V0 u) D7 @' aAREA    | LongestLength
. T& V5 Q" p3 AFontana |          31 Q. @7 G! [* T7 `7 z, ~
RC      |          2
, F, e- p! L, X' ]/ ^我将如何在MS Sql 2005上执行此操作?
( O& k7 b2 ~2 D& y- W; y& U                ; ~" g$ G- Z! w$ c+ q
解决方案:6 p1 ]. a( _. F/ s" C# A
                9 x: h9 ]% q6 H0 Z  H

7 f" \5 m& d: h, S# \! u
3 s% T# C1 `: }6 b5 [. ~- e3 _5 r+ {                一种方法是使用遍历每一行的递归CTE。如果该行符合条件(增加同一区域的订单号),则将链长增加一。如果没有,则启动一个新链:7 S4 Q9 l5 j# p, U. ^" H
; with  numbered as. C) i' T3 I5 u1 r! v
        (
6 q) h. w$ E3 v1 l        select  row_number() over (order by area, eventtime) rn2 b$ m5 T5 f$ {- H
        ,       *
2 n5 k- E- M4 w/ r5 p' p6 v: B        from    Table12 B6 M2 x! f3 O# F2 f
        )
( L: h2 r7 P# O1 c" Y4 z,       recurse as4 i- y8 o( Z' ?! G2 f: J
        (
" N/ O& h& g$ M5 T        select  rn
; ^5 T, R6 ~' Z1 U1 `% ^& K( p        ,       area! u$ ~2 J& C- l  y2 ^4 \
        ,       OrderNumber
" z& Y& ?0 |# U& n+ l        ,       1 as ChainLength
$ V2 e& x4 ^, [9 j        from    numbered, `4 K& X8 `+ |! _# }. K5 U/ S
        where   rn = 1$ s' \- K  J7 }  T2 l" @
        union all) p) x5 G1 H- D6 n; V" @
        select  cur.rn  d3 _6 c) v8 j3 F
        ,       cur.area
' p9 Q9 w  ~, n4 |8 d) _        ,       cur.OrderNumber* |, z3 ]3 Y" d) x
        ,       case
/ g* T  Q( s0 Z+ z7 U5 o                when cur.area = prev.area 5 F* j/ R  g* Q: [
                     and cur.OrderNumber > prev.OrderNumber $ z+ O+ r- R: |' E
                     then prev.ChainLength + 1  G' r) o/ F3 ]  g/ v+ x# `, [
                else 13 F9 E. K# o5 f! ^) r
                end# G3 J9 l  n' W3 a, D# e) ?
        from    recurse prev( _/ ^- y2 G! [
        join    numbered cur
+ {& A; F$ @8 V# M2 J  G        on      prev.rn + 1 = cur.rn
) g9 r' W* g$ T4 k6 R( A9 H) a        )
- S- M& r! X3 s$ g1 }5 ]select  area
* Z) f% x' }7 M" g3 G" \, c0 h,       max(ChainLength); x; L- p( c5 a  h5 x, P
from    recurse
1 h0 C3 G* E& J2 F) u  pgroup by
$ k1 c$ i/ \" p! ?% `* ]5 C$ J        area6 K+ W% M, [, u" w" s# y
SQL Fiddle的实时示例。
. F6 p* [, V& t另一种方法是使用查询查找“中断”,即以相同区域的顺序编号递增的序列结束的行。中断之间的行数是长度。
4 k/ l1 n. [7 f# Q1 P7 Q; with  numbered as, Q% ^" v  r" a6 S8 |4 H2 _
        (/ z8 j" k1 e* o1 Q' {
        select  row_number() over (order by area, eventtime) rn4 T/ O+ O) Q7 o
        ,       *
. C/ D7 e9 u: b6 d3 h4 U+ e' q2 X        from    Table1 t1' P2 A7 y9 O  V0 d) J! W1 e' _' s& \
        ): w  M* A- A$ f" l
        -- Select rows that break an increasing chain
8 B9 F9 ?4 E2 h6 B# D$ Q3 f,       breaks as3 r% H; a4 M$ f5 _/ q1 Q
        (
8 h* \! O9 o$ f: Z        select  row_number() over (order by cur.rn) rn2
9 ?- A  f3 q$ b        ,       cur.rn1 O5 K% W- }' M$ }& W) P
        ,       cur.Area4 R! Z8 s8 V1 h& `& ?% M
        from    numbered cur
5 y% `& j3 p- D6 S3 w% s/ g7 z        left join
  o  h2 N  h! M& M: ]" B# y                numbered prev8 T1 L& h0 \! B* v
        on      cur.rn = prev.rn + 1
) l5 T$ u1 l7 X7 _! Z1 H5 Z0 O$ T        where   cur.OrderNumber  prev.Area
7 d. }5 o4 g5 Q# ?4 d" x! c                or prev.Area is null
2 k& d! X) y1 c7 O: z4 B6 C1 a        )) o  M- w! ?* f( V! z3 q
        -- Add a final break after the last row
5 r4 a: K. {2 D% b7 T2 y9 x,       breaks2 as! Q, M) O  C7 e/ G) i+ [
        (! b/ R0 ]8 {2 R4 Z" L9 \
        select  *8 p$ B/ ]+ ^' h
        from    breaks* {1 K9 X8 p. O  K" I
        union all7 Z" U, v" c8 S( y
        select  count(*) + 1
! l" Z: @0 ~7 H9 f        ,       max(rn) + 1: B% j' h' n# j% s7 ]
        ,       null  w0 h1 S$ Q5 w# i+ S
        from    breaks/ a( W' F+ b* G4 n! \( t6 w
        )
# U% B/ Z6 q% qselect  series_start.area  G+ W# S- ]4 x
,       max(series_end.rn - series_start.rn)9 ?. T) S" [/ h* b2 B( b
from    breaks2 series_start( u9 H) l5 |6 y2 p" O& M! P9 v
join    breaks2 series_end; d0 s$ [/ R  G, M
on      series_end.rn2 = series_start.rn2 + 1# w1 M  D( \) L2 T, Y) p. z) K
group by/ t  G4 G. j5 J* @" Y) h/ H
        series_start.area
$ K5 F( k( R  c+ Z, R# q" j  [SQL Fiddle的实时示例。
分享到:
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则