10個SQL技巧之四:找到連續的沒有間隙的最大系列的日期
現在我們正在進行宣告性程式設計,我們不關心維護任何狀態和記憶體中的計數器。我們希望以線上分析SQL的形式表達這一點。即考慮這些資料:
| LOGIN_TIME | | --------------------- | | 2014-03-18 05:37:13 | | 2014-03-16 08:31:47 | | 2014-03-16 06:11:17 | | 2014-03-16 05:59:33 | | 2014-03-15 11:17:28 | | 2014-03-15 10:00:11 | | 2014-03-15 07:45:27 | | 2014-03-15 07:42:19 | | 2014-03-14 09:38:12 | |
這沒有多大幫助。讓我們從時間戳中刪除小時。這很簡單:
SELECT DISTINCT cast(login_time AS DATE) AS login_date FROM logins WHERE user_id = :user_id |
輸出:
| LOGIN_DATE | | ------------ | | 2014-03-18 | | 2014-03-16 | | 2014-03-15 | | 2014-03-14 | |
現在,我們已經瞭解了視窗函式,讓我們只為每個日期新增一個簡單的行號:
SELECT login_date, row_number() OVER (ORDER BY login_date) FROM login_dates |
輸出:
| LOGIN_DATE | RN | | ------------ | ---- | | 2014-03-18 | 4 | | 2014-03-16 | 3 | | 2014-03-15 | 2 | | 2014-03-14 | 1 | |
還很容易。現在,如果不是單獨選擇這些值,我們會減去它們會發生什麼?
SELECT login_date - row_number() OVER (ORDER BY login_date) FROM login_dates |
我們得到這樣的結果:
| LOGIN_DATE | RN | GRP | | ------------ | ---- | ------------ | | 2014-03-18 | 4 | 2014-03-14 | | 2014-03-16 | 3 | 2014-03-13 | | 2014-03-15 | 2 | 2014-03-13 | | 2014-03-14 | 1 | 2014-03-13 | |
哇。有趣。所以,14 - 1 = 13,15 - 2 = 13,16 - 3 = 13,但是18 - 4 = 14.
這個動作代表一個簡單的判斷:
- ROW_NUMBER()沒有間隙。這就是它的定義方式
- 但是,我們的資料確實如此
因此,當我們從“連續”系列的非連續日期中減去“無間隙”系列連續整數時,我們將為連續日期的每個“無間隙”子系列獲得相同的日期,我們將再次獲得新的有間隙的日期系列。
這意味著我們現在只需GROUP BY這個任意日期值:
SELECT min(login_date), max(login_date), max(login_date) - min(login_date) + 1 AS length FROM login_date_groups GROUP BY grp ORDER BY length DESC |
我們已經完成了。已找到最大系列的連續日期,沒有間隙:
| MIN | MAX | LENGTH | |------------|------------|--------| | 2014-03-14 | 2014-03-16 | 3 | | 2014-03-18 | 2014-03-18 | 1 | |
完整查詢為:
WITH login_dates AS ( SELECT DISTINCT cast(login_time AS DATE) login_date FROM logins WHERE user_id = :user_id ), login_date_groups AS ( SELECT login_date, login_date - row_number() OVER (ORDER BY login_date) AS grp FROM login_dates ) SELECT min(login_date), max(login_date), max(login_date) - min(login_date) + 1 AS length FROM login_date_groups GROUP BY grp ORDER BY length DESC |
查詢本身確實非常簡單和優雅。你決不能以比這更精簡的方式實現一些命令式演算法。
相關文章
- SQL 獲取SQL Server中兩個日期之間的所有日期SQLServer
- SQL datediff用法( 返回兩個日期之間的間隔)SQL
- JavaScript 演算法:計算最大連續日期區間JavaScript演算法
- SQL 獲取SQL Server中日期最近7天之間的所有日期SQLServer
- SQL 讀取不連續的第30到40之間的資料SQL
- AI 四小龍之間沒有戰爭AI
- 10 個面試技巧幫你找到最好的工作面試
- sql關於連續日期的統計報表問題SQL
- leetcode —— 1004. 最大連續1的個數 IIILeetCode
- js獲取兩個日期之間有哪些具體的日期程式碼例項JS
- UICollectionView間隙的坑UIView
- 給出一個由[-100,100]之間整陣列成的陣列,求其相加和最大的連續子陣列 輸入 一個連續整陣列成的陣列 輸出 子陣列相加的最大值 樣例輸入 -......陣列
- LeetCode-485-最大連續 1 的個數LeetCode
- SQL 第30到40之間的資料讀取不連續的問題SQL
- hive生成連續的時間和連續的數Hive
- 直播原始碼,獲取兩個日期之間的所有日期原始碼
- 連續子陣列的最大和陣列
- 查詢兩個日期之間的資料
- 一個連續動作空間的SAC的例子
- leetcode力扣 1004. 最大連續1的個數 IIILeetCode力扣
- javascript如何計算兩個日期之間的時間間隔JavaScript
- 計算2個日期間的所有日期
- Sql Server系列:日期和時間函式SQLServer函式
- ORACLE 計算2個日期之間的天數Oracle
- 25:計算兩個日期之間的天數
- Oracle計算兩個日期之間的天數Oracle
- ios input 鍵盤收起頁面底部有間隙沒有自動還原iOS
- DB2中的限制之四日期時間的限制 (轉)DB2
- 巧妙讓兩個span元素中間的空格不再有間隙
- win10 工作列只有時間沒有日期怎麼解決Win10
- 最大連續子陣列和的實現陣列
- Java 中,如何計算兩個日期之間的差距?Java
- 表的連線是指在一個SQL語句中通過表與表之間的關連SQL
- sql server中對時間日期的操作SQLServer
- 【演算法題解】485. 最大連續1的個數 - Java演算法Java
- 給定陣列中找到最大的兩個數陣列
- 帶領團隊發揮最大潛能的10個技巧
- 10個面試技巧幫你找到好工作面試