有個需求要做找出連續出勤超過五天的人
下圖是Log表

期望結果找出 如下表連續出勤超過五天的人

這是一個很經典的 [SQL連續範圍] 問題
解決連續範圍問題,運用到一個小小技巧
連續資料有個特性是一組連續範圍數值 - 有順序的值  結果是一樣的
如下圖 我們可發現有三組連續數字
DECLARE  @t  TABLE( a int );
INSERT into @t VALUES(1);
INSERT into @t VALUES(2);
INSERT into @t VALUES(3);
INSERT into @t VALUES(100);
INSERT into @t VALUES(101);
INSERT into @t VALUES(103);
INSERT into @t VALUES(104);
INSERT into @t VALUES(105);
+-----+
| a   |
+-----+ 
|   1 |
|   2 |
|   3 |
| 100 |
| 101 |
| 103 |
| 104 |
| 105 |
+-----+ 
分別是
- 1~3
 - 100~101
 - 103~105
 
第一步
多新增一組序號(RK)
- 將資料按照順序排巡(RK)
 
就可得到如下表
+-----+------+
| num | RK   |
+-----+------+
|   1 |    1 |
|   2 |    2 |
|   3 |    3 |
| 100 |    4 |
| 101 |    5 |
| 103 |    6 |
| 104 |    7 |
| 105 |    8 |
+-----+------+
有了上表我們就可以變魔術摟~~請看
利用(num - RK) 可以得到分組的資料(真是太神奇啦XD)
+-----+------+-----------+
| num | RK   | num - RK  |
+-----+------+-----------+
|   1 |    1 |    0      |
|   2 |    2 |    0      |
|   3 |    3 |    0      |
| 100 |    4 |   96      |
| 101 |    5 |   96      |
| 103 |    6 |   97      |
| 104 |    7 |   97      |
| 105 |    8 |   97      |
+-----+------+-----------+
有了上面概念後就可運用此腳本來取得分組資訊
SELECT MIN(T.num) fromNum,MAX( T.num) TONum
FROM
(
	SELECT  *,num - ROW_NUMBER() OVER(ORDER BY num) RKG
	FROM @t
) AS T 
GROUP BY RKG
Result:
fromNum     TONum
----------- -----------
1           3
100         101
103         105
回歸正題
題目中的連續資料是日期,所以我們無法像數字一樣直接相減排序。
假如可以按照日期來排出序號該有多好...
好在SQL_Server有提供一個關鍵字是 OVER 視窗函式
我們就可運用 ROW_NUMBER() + OVER  來排序
話不多說貼上程式碼XD
DECLARE @T TABLE 
(
	Name VARCHAR(50),
    Dates DATE
);
INSERT INTO @T VALUES
('Tom','2017/10/10'),
('Tom','2017/10/11'),
('Tom','2017/10/12'),
('Tom','2017/10/13'),
('Tom','2017/10/14'),
('AMY','2017/10/10'),
('AMY','2017/10/11'),
('AMY','2017/10/12');
SELECT Name,MIN(DATES) AS [StartDate],MAX(DATES) AS [EndDate]
FROM 
(
	SELECT *, ROW_NUMBER() OVER(ORDER BY [Name]) - ROW_NUMBER() OVER (PARTITION BY [Name] ORDER BY DATES) as rn
	FROM @T
)AS T
GROUP BY NAME
HAVING COUNT(RN) > 4
小結 :
查找連續範圍問題重點在如何把資料分群
只要分群後就只要Group by 搂^^
如果本文對您幫助很大,可街口支付斗內鼓勵石頭^^

            