表 t1(year, month, day) 記錄訪問日誌,同一天可能多筆記錄,需統計每月不重複天數。
+------+-------+------+ | year | month | day | +------+-------+------+ | 2000 | 01 | 01 | | 2000 | 01 | 20 | | 2000 | 01 | 30 | | 2000 | 02 | 02 | | 2000 | 02 | 23 | | 2000 | 03 | 13 | | 2000 | 02 | 23 | -- 重複: 2月23日出現兩次 +------+-------+------+
SELECT year, month, COUNT(day) AS days FROM t1 GROUP BY year, month; -- 結果: 2月統計為 3 天 (實際僅 2 天)
SELECT year, month,
BIT_COUNT(BIT_OR(1 << day)) AS days
FROM t1
GROUP BY year, month;
-- 結果: 2月正確統計為 2 天
1 << day:將 1 左移 day 位,產生只有第 day 位為 1 的二進制數
100 (二進制) = 410000000000000000000000 = 8,388,608BIT_OR():對群組內所有值執行位元 OR 運算,合併所有「天」的位標記
100 | 10000000000000000000000 | 100 = 10000000000000000000100BIT_COUNT():計算二進制中 1 的個數,即不重複天數
SELECT year, month, COUNT(DISTINCT day) AS days FROM t1 GROUP BY year, month;
推薦使用:語意清晰、可讀性強、效能相當 (MySQL 5.7+ 優化器對 DISTINCT 聚合有專門優化)。
| 函數 | 說明 | 範例 |
|---|---|---|
BIT_COUNT(N) | 回傳長整數 N 二進制中 1 的個數 | BIT_COUNT(29) = 4 (11101) |
BIT_OR(expr) | 回傳群組內所有值位元 OR 結果 (64-bit 精度) | BIT_OR(1|2|4) = 7 |
BIT_AND(expr) | 回傳群組內所有值位元 AND 結果 | BIT_AND(7|3) = 3 |
BIT_XOR(expr) | 回傳群組內所有值位元 XOR 結果 | BIT_XOR(1|2|3) = 0 |