今天想回答sql server - Select Consecutive Numbers in SQL爬文發現,自己居然一直不知道spt_values用法 (羞愧Orz..),所以寫文章分享給不小心不知道的版友。
連續整數是一個常見的SQL需求,而SQL-Server的開發者除了遞迴
的方式外,其實還有一個方式能解決需求,並且效率更好。
舉例 :
在S.O想要知道某個帳號在24小時每小時發文comment總次數,來研究使用的時間利用情況,如下圖,我們能清楚了解該用戶在2-9點期間都是在休息的。
小時 總評論次數
1 497
2 0
3 0
4 0
5 0
6 0
7 0
8 0
9 27
10 140
11 311
12 11
13 386
14 242
15 318
16 193
17 42
18 261
19 423
20 86
21 364
22 132
23 223
24 95
因為我們都知道S.O使用的是SQL-Server資料庫,通常第一直覺作法是使用recursive CTE
(遞迴)解決
e.g:
with cte_hours as (
select 1 as hour
union all
select hour + 1
from cte_hours
where hour < 24
)
select h.hour ,c.count
from cte_hours h
left join (
select datepart(hour, creationdate) as hour,count(1) count
from comments
where userid = '9131476'
group by datepart(hour, creationdate)
) c on h.hour = c.hour
order by h.hour;
online demo link : consecutive number query demo - Stack Exchange Data Explorer
但這樣這會感覺殺雞用牛刀
,並且遞迴數量一大效率問題就會出現。
其實在master
有一個表格spt_values
我們可以拿來利用,原因是它本身有一個欄位number就是現成的連續整數,可以將SQL改成以下這樣 :
select h.hour ,c.count
from (
select top 24 number + 1 as hour from master..spt_values
where type = 'P'
) h
left join (
select datepart(hour, creationdate) as hour,count(1) count
from comments
where userid = '9131476'
group by datepart(hour, creationdate)
) c on h.hour = c.hour
order by h.hour;
online demo link : consecutive number query demo - Stack Exchange Data Explorer
以上方式算是取巧
,但優點是通用性
好,不需要新增任何表格直接就能使用。
那何不換位思考,嘗試cross join
呢,這樣就有2048*2048數量能使用了,但這時就需要用到rownumber
函數了
select top 10000 row_number() over (order by t1.number) as number
from master..spt_values T1,master..spt_values T2
where T1.type = 'P'
以上方式終究還是有點效率不完美,假如真的遇到大量數據需要連號 + 多列
情況,麻煩建立一個實體Table + PK
假如平常我的回答或是文章有幫助到你,可以幫我的
Wei | LinkedIn
或是Github點個追蹤或是Star,謝謝你 ^_^
Wei | Github
還可以 join 更多個啦. 2048 x 2048 的結果,再自己join. 就超多的啦.
這個產生以後,存成 table. 一百,一萬.搭配 top 這樣就可以組合出許多.