号码连续分段问题

客户有一个判断号码连续的问题,这种问题用分析函数解决是比较有代表性的。
表结构和数据为:

SQL> SELECT * FROM tab1;
        ID CA REG
---------- -- ---
       100 11 S
       101 11 S
       102 11 N
       103 11 N
       104 11 N
       105 0  S
       106 0  S
       107 0  S
       108 0  N
       109 0  N
       110 0  N
       111 11 S
       112 11 S
       113 11 N
       114 11 N
       115 11 N
       116 0  S
       117 0  S
       118 0  N
       119 0  N
       120 0  N
       121 11 S
       122 11 S
       123 11 S
       124 11 S
       125 11 S
       126 11 S
       127 11 S
       128 11 S
       129 11 S
       130 11 S
       200 11 S
       201 11 S
       202 11 N
       203 11 N
       204 11 N
       205 0  S
       206 0  S
       207 0  S
       208 0  N
       209 0  N
       210 0  N
       211 11 S
       212 11 S
       213 11 N
       214 11 N
       215 11 N
       300 11 S
       301 11 S
       302 11 N
       303 11 N
       304 11 N
       305 0  S
       306 0  S
       307 0  S
       308 0  N
       309 0  N
       310 0  N
       311 11 S
       312 11 S
       313 11 N
       314 11 N
       315 11 N
63 ROWS selected.

需求是找到一组连续ID的最小值和最大值,要求除了数值连续外,另外两个字段也必须相同,否则认为是新的号段。
简单的说,最终需要的结果类似:

100-101 11 S
102-104 11 N
105-107 00 S
108-110 00 N
... ...
200-201 11 S
202-204 11 N
205-207 00 S
208-210 00 N

其实这个问题使用分析函数并不复杂,第一步是通过构造列判断是否连续,然后进一步构造出分组的依据,这里使用了一个小技巧,将1变成0,而从保证一个号段内SUM汇总的结果是相同的,最后GROUP BY就可以得到最终结果:

SQL> SELECT MIN(id) || '-' || MAX(id) flag,
  2     card_type,
  3     region
  4  FROM
  5  (
  6     SELECT id, card_type, region, SUM(flag) OVER(ORDER BY id) flag
  7     FROM (
  8             SELECT id, card_type, region,
  9                     nvl(id-lag(id, 1) OVER(ORDER BY id)
 10                             + CASE WHEN card_type = lag(card_type, 1) OVER(ORDER BY id) THEN 0 ELSE 10 END
 11                             + CASE WHEN region = lag(region, 1) OVER(ORDER BY id) THEN 0 ELSE 10 END
 12                             , 1) -1 flag
 13             FROM tab1
 14     )
 15  )
 16  GROUP BY card_type, region, flag
 17  ORDER BY 1;
FLAG                 CA REG
-------------------- -- ---
100-101              11 S
102-104              11 N
105-107              0  S
108-110              0  N
111-112              11 S
113-115              11 N
116-117              0  S
118-120              0  N
121-130              11 S
200-201              11 S
202-204              11 N
205-207              0  S
208-210              0  N
211-212              11 S
213-215              11 N
300-301              11 S
302-304              11 N
305-307              0  S
308-310              0  N
311-312              11 S
313-315              11 N
21 ROWS selected.
This entry was posted in ORACLE and tagged , , , . Bookmark the permalink.

Leave a Reply

Your email address will not be published. Required fields are marked *