如何获得任何连续范围内的最大值
How to get the biggest value in any consecutive range
考虑无符号整数索引列中的以下值:
1
2
3
3
2
4
6
8
9
对于任何提供的数字,我想获得其连续范围内的最大值(当存在下一个连续数字时继续前进)。
例如,假设我们得到的输入是2
; 3
和 4
的连续值确实存在于列表中(无论它们的顺序如何),但 5
不存在;因此我们的连续范围将是 2,3,4
;因此期望值将是 4
:这个连续范围内的最大值;提供 1
、3
或 4
中的任何一个后,还应产生 4
。因此:
input expected output
-------------------------------
1,2,3,4 4 -- any value of the input yields 4
5 5 -- the input value doesn't even exist in the list
6 6 -- it's the only value
7 7 -- the input value doesn't even exist in the list
8,9 9
那么,如何使用MySQL获得任何连续范围内的最大值?
这可能是一个间隙隔离问题,可能需要使用window函数来解决,CTE递归来解决。
首先,我们可以尝试使用CTE递归生成器调用startnum
范围从最小数到最大的数据(来自我们的样本是1
,9
),因为他们之间少了一些数字。
下一步我们可能会计算 grp
即 gap-and-island 问题特征逻辑。
逻辑可能如下。
continuous(overlapping) data is that a set (continuous range of sequence) - (values based on a certain order of conditions sequence)
yields the same grouping.
所以我们可以使用
- 序列的连续范围:startNum
- 取值按一定顺序:
dense_rank
window函数.
使用这个逻辑我们可能会得到一个 grp
列作为 sqlfiddle
查询#1
WITH RECURSIVE cte AS(
SELECT MIN(val) startNum, MAX(val) endNum
FROM T
UNION ALL
SELECT startNum + 1,endNum
FROM cte
WHERE startNum + 1 <= endNum
)
SELECT GROUP_CONCAT(DISTINCT startNum) input,
MAX(startNum) 'expected output'
FROM (
SELECT val,
startNum ,
startNum - cast(dense_rank() OVER(ORDER BY val)as signed) grp
FROM cte t1
LEFT JOIN T t2
ON t1.startNum = t2.val
) t1
GROUP BY grp
ORDER BY 2;
input
expected output
1,2,3,4
4
5
5
6
6
7
7
8,9
9
使用递归 CTE:
WITH RECURSIVE cte AS (
SELECT x FROM tablename WHERE x = ?
UNION
SELECT t.x
FROM tablename t INNER JOIN cte c
ON t.x = c.x + 1
)
SELECT COALESCE(MAX(x), ?) x FROM cte;
参见demo。
或者,使用 DENSE_RANK()
window 函数:
SELECT COALESCE(MAX(CASE WHEN x = rn THEN x END), ?) x
FROM (
SELECT x, DENSE_RANK() OVER (ORDER BY x) + ? rn
FROM tablename
WHERE x > ? AND EXISTS (SELECT * FROM tablename WHERE x = ?)
) t
参见demo。
将 ?
替换为您想要的 input
值。
考虑无符号整数索引列中的以下值:
1
2
3
3
2
4
6
8
9
对于任何提供的数字,我想获得其连续范围内的最大值(当存在下一个连续数字时继续前进)。
例如,假设我们得到的输入是2
; 3
和 4
的连续值确实存在于列表中(无论它们的顺序如何),但 5
不存在;因此我们的连续范围将是 2,3,4
;因此期望值将是 4
:这个连续范围内的最大值;提供 1
、3
或 4
中的任何一个后,还应产生 4
。因此:
input expected output
-------------------------------
1,2,3,4 4 -- any value of the input yields 4
5 5 -- the input value doesn't even exist in the list
6 6 -- it's the only value
7 7 -- the input value doesn't even exist in the list
8,9 9
那么,如何使用MySQL获得任何连续范围内的最大值?
这可能是一个间隙隔离问题,可能需要使用window函数来解决,CTE递归来解决。
首先,我们可以尝试使用CTE递归生成器调用startnum
范围从最小数到最大的数据(来自我们的样本是1
,9
),因为他们之间少了一些数字。
下一步我们可能会计算 grp
即 gap-and-island 问题特征逻辑。
逻辑可能如下。
continuous(overlapping) data is that a set
(continuous range of sequence) - (values based on a certain order of conditions sequence)
yields the same grouping.
所以我们可以使用
- 序列的连续范围:startNum
- 取值按一定顺序:
dense_rank
window函数.
使用这个逻辑我们可能会得到一个 grp
列作为 sqlfiddle
查询#1
WITH RECURSIVE cte AS(
SELECT MIN(val) startNum, MAX(val) endNum
FROM T
UNION ALL
SELECT startNum + 1,endNum
FROM cte
WHERE startNum + 1 <= endNum
)
SELECT GROUP_CONCAT(DISTINCT startNum) input,
MAX(startNum) 'expected output'
FROM (
SELECT val,
startNum ,
startNum - cast(dense_rank() OVER(ORDER BY val)as signed) grp
FROM cte t1
LEFT JOIN T t2
ON t1.startNum = t2.val
) t1
GROUP BY grp
ORDER BY 2;
input | expected output |
---|---|
1,2,3,4 | 4 |
5 | 5 |
6 | 6 |
7 | 7 |
8,9 | 9 |
使用递归 CTE:
WITH RECURSIVE cte AS (
SELECT x FROM tablename WHERE x = ?
UNION
SELECT t.x
FROM tablename t INNER JOIN cte c
ON t.x = c.x + 1
)
SELECT COALESCE(MAX(x), ?) x FROM cte;
参见demo。
或者,使用 DENSE_RANK()
window 函数:
SELECT COALESCE(MAX(CASE WHEN x = rn THEN x END), ?) x
FROM (
SELECT x, DENSE_RANK() OVER (ORDER BY x) + ? rn
FROM tablename
WHERE x > ? AND EXISTS (SELECT * FROM tablename WHERE x = ?)
) t
参见demo。
将 ?
替换为您想要的 input
值。