業務中常需從離散的數字序列 (如設備運行號、流水號) 中找出「連續區間」。本文介紹經典的行號差值分組法:利用連續數字與其行號的差值恆定特性,單條 SQL 高效解決。
對於連續數列 1,2,3,4,5,其行號 (1,2,3,4,5) 與數值差值皆為 0;若序列斷裂 1,2, 5,6,前兩差值為 0,後兩差值為 3。**差值相同即屬同一連續區間**。
WITH sorted AS (
SELECT
CAST(running_number AS UNSIGNED) AS rn_val,
ROW_NUMBER() OVER (ORDER BY CAST(running_number AS UNSIGNED)) AS seq
FROM device_data
WHERE device_id = 13
)
, diff_calc AS (
SELECT rn_val, seq, (rn_val - seq) AS diff_val
FROM sorted
)
SELECT
MIN(rn_val) AS range_start,
MAX(rn_val) AS range_end,
COUNT(*) AS continuity_count
FROM diff_calc
GROUP BY diff_val
ORDER BY range_start;
WITH sorted AS (
SELECT CAST(running_number AS UNSIGNED) AS rn_val,
ROW_NUMBER() OVER (ORDER BY CAST(running_number AS UNSIGNED)) AS seq
FROM device_data WHERE device_id = 13
),
diff_calc AS (
SELECT rn_val, (rn_val - seq) AS diff_val FROM sorted
)
SELECT MIN(rn_val) AS min_val, MAX(rn_val) AS max_val
FROM diff_calc
GROUP BY diff_val
ORDER BY min_val;
SELECT MIN(rn_val) AS min_val, MAX(rn_val) AS max_val
FROM (
SELECT
CAST(running_number AS UNSIGNED) AS rn_val,
@row := @row + 1 AS seq,
(CAST(running_number AS UNSIGNED) - @row) AS diff_val
FROM device_data, (SELECT @row := 0) r
WHERE device_id = 13
ORDER BY rn_val
) t
GROUP BY diff_val
ORDER BY min_val;
PARTITION BY group_id 中應用窗口函數。參考:《MySQL技術內幕:SQL編程》2.6.2 連續範圍問題。