需求:對數值欄位依多個區間(如 0-9、10-19、20-49、50-99、100+)統計筆數。傳統寫法需多次掃描或 UNION ALL,本文介紹**單次掃描 + 位元旗標 + GROUP BY** 的高效技巧。
value / boundary,結果 ≥1 表示落在該區間或更高。CONVERT(BIT, value / boundary) 產生 0/1 旗標(Bit 型別僅佔 1 位元)。-- 建立測試資料
DECLARE @tb TABLE (id INT IDENTITY(1,1), num INT);
INSERT INTO @tb (num) VALUES (1),(10),(20),(25),(12),(15),(13),(22),(5),(50),(80),(110);
-- 單次掃描多區間統計
SELECT
CASE (overall + over10 + over20 + over50 + over100)
WHEN 1 THEN '0-9'
WHEN 2 THEN '10-19'
WHEN 3 THEN '20-49'
WHEN 4 THEN '50-99'
ELSE '100+'
END AS [區間],
COUNT(*) AS [筆數]
FROM (
SELECT
1 AS overall, -- 基準旗標(所有行皆為1)
CONVERT(BIT, num/10) AS over10, -- ≥10
CONVERT(BIT, num/20) AS over20, -- ≥20
CONVERT(BIT, num/50) AS over50, -- ≥50
CONVERT(BIT, num/100) AS over100 -- ≥100
FROM @tb
) AS flags
GROUP BY (overall + over10 + over20 + over50 + over100)
ORDER BY [區間];
區間 筆數 0-9 2 10-19 4 20-49 3 50-99 2 100+ 1
| num | overall | over10 | over20 | over50 | over100 | 總和 | 區間 |
|---|---|---|---|---|---|---|---|
| 5 | 1 | 0 | 0 | 0 | 0 | 1 | 0-9 |
| 12 | 1 | 1 | 0 | 0 | 0 | 2 | 10-19 |
| 25 | 1 | 1 | 1 | 0 | 0 | 3 | 20-49 |
| 80 | 1 | 1 | 1 | 1 | 0 | 4 | 50-99 |
| 110 | 1 | 1 | 1 | 1 | 1 | 5 | 100+ |
每個區間邊界對應一個 Bit 旗標,總和即為區間索引,**單次表掃描即可完成所有區間計數**。
若區間邊界儲存於設定表,可動態構建旗標欄位:
DECLARE @boundaries TABLE (seq INT, bound INT, label VARCHAR(20));
INSERT @boundaries VALUES (1,10,'0-9'),(2,20,'10-19'),(3,50,'20-49'),(4,100,'50-99'),(5,999999,'100+');
DECLARE @sql NVARCHAR(MAX) = N'SELECT ';
SELECT @sql += N'CONVERT(BIT, num/' + CAST(bound AS VARCHAR) + N') AS f' + CAST(seq AS VARCHAR) + N','
FROM @boundaries ORDER BY seq;
SET @sql = LEFT(@sql, LEN(@sql)-1) + N' FROM @tb'; -- 實際執行需動態 SQL
-- 後續 GROUP BY SUM(f1+f2+...) 並 JOIN @boundaries 取 label
此技巧適用於報表儀表板、監控告警統計、數值分佈直方圖等**固定區間、高頻統計**場景,顯著降低查詢延遲。