在MySQL中查找顺序值之间的间隙
更新2:我已经解决了最初的两个问题。但当我做了建议滚动更新的更改时,另一个出现了 我使用MySQL 5.7。更新:现在迁移到MySQL 8.0 我有这张桌子:在MySQL中查找顺序值之间的间隙,mysql,sql,Mysql,Sql,更新2:我已经解决了最初的两个问题。但当我做了建议滚动更新的更改时,另一个出现了 我使用MySQL 5.7。更新:现在迁移到MySQL 8.0 我有这张桌子: +------+ | unit | +------+ | 1000 | | 1040 | | 1555 | | 1600 | | 3020 | | 7000 | +------+ +-------------+ | unit | +-------------+ | 3079 | | 3130 |
+------+
| unit |
+------+
| 1000 |
| 1040 |
| 1555 |
| 1600 |
| 3020 |
| 7000 |
+------+
+-------------+
| unit |
+-------------+
| 3079 |
| 3130 |
| 3185 |
+-------------+
我使用以下存储过程来查找范围之间的间隙。它很有用,因为它具有良好的性能,并且当间隙的大小达到我们期望的最小值时停止:
CREATE DEFINER=`development`@`%` PROCEDURE `stack_overflow_question`(req_range_start VARCHAR(32), IN req_range_end VARCHAR(32), IN req_quantity INT(11))
BEGIN
SET @range_start = req_range_start;
SET @range_end = req_range_end;
SET @demanded_quantity = req_quantity; # Implementation for calculation of gap size.
SET @quantity_aggregated = 0; # Implementation for calculation of gap size.
SELECT
interval_start,
interval_end,
@quantity := interval_end - interval_start + 1 AS quantity,
@quantity_aggregated := @quantity_aggregated + @quantity AS quantity_aggregated
FROM (
SELECT
@interval_start := @rownum := @rownum + 1 AS interval_start,
@interval_end := IF (@rownum = unit, 0, @rownum := IF ((unit <= @range_end), unit, @range_end + 1)) - 1 AS interval_end
FROM (
SELECT @rownum := (SELECT MIN(@range_start - 1) FROM item)
) AS a
JOIN item
ORDER BY unit
) AS z
WHERE NOT interval_end <= 0 AND interval_start <= @range_end
HAVING @quantity_aggregated <= @demanded_quantity; # This makes the query stop when we have reached the desired size of gap.
END
结果:
+----------------+--------------+----------+---------------------+
| interval_start | interval_end | quantity | quantity_aggregated |
+----------------+--------------+----------+---------------------+
| 1001 | 1039 | 39 | 39 |
| 1041 | 1554 | 514 | 553 |
+----------------+--------------+----------+---------------------+
失败示例,1:未考虑最后一行。固定的
结果:
+----------------+--------------+----------+---------------------+
| interval_start | interval_end | quantity | quantity_aggregated |
+----------------+--------------+----------+---------------------+
| 1001 | 1039 | 39 | 39 |
| 1041 | 1554 | 514 | 553 |
| 1556 | 1599 | 44 | 597 |
| 1601 | 3019 | 1419 | 2016 |
| 3021 | 6999 | 3979 | 5995 |
+----------------+--------------+----------+---------------------+
+----------------+--------------+----------+---------------------+
| interval_start | interval_end | quantity | quantity_aggregated |
+----------------+--------------+----------+---------------------+
| 1001 | 1000 | 0 | 0 |
| 1002 | 1000 | -1 | -1 |
| 1002 | 1000 | -1 | -2 |
| 1002 | 1000 | -1 | -3 |
| 1002 | 1000 | -1 | -4 |
+----------------+--------------+----------+---------------------+
interval_start interval_end quantity quantity_aggregated
1001 1039 39 39
1041 1554 514 553
1556 1599 44 597
1601 3019 1419 2016
3021 6999 3979 5995
7001 9000 2000 7995
预期结果:
+----------------+--------------+----------+---------------------+
| interval_start | interval_end | quantity | quantity_aggregated |
+----------------+--------------+----------+---------------------+
| 1001 | 1039 | 39 | 39 |
| 1041 | 1554 | 514 | 553 |
| 1556 | 1599 | 44 | 597 |
| 1601 | 3019 | 1419 | 2016 |
| 3021 | 6999 | 3979 | 5995 |
| 7001 | 9000 | 2000 | 7995 | < additional row showing the end of the range.
+----------------+--------------+----------+---------------------+
结果:
+----------------+--------------+----------+---------------------+
| interval_start | interval_end | quantity | quantity_aggregated |
+----------------+--------------+----------+---------------------+
| 1001 | 1039 | 39 | 39 |
| 1041 | 1554 | 514 | 553 |
| 1556 | 1599 | 44 | 597 |
| 1601 | 3019 | 1419 | 2016 |
| 3021 | 6999 | 3979 | 5995 |
+----------------+--------------+----------+---------------------+
+----------------+--------------+----------+---------------------+
| interval_start | interval_end | quantity | quantity_aggregated |
+----------------+--------------+----------+---------------------+
| 1001 | 1000 | 0 | 0 |
| 1002 | 1000 | -1 | -1 |
| 1002 | 1000 | -1 | -2 |
| 1002 | 1000 | -1 | -3 |
| 1002 | 1000 | -1 | -4 |
+----------------+--------------+----------+---------------------+
interval_start interval_end quantity quantity_aggregated
1001 1039 39 39
1041 1554 514 553
1556 1599 44 597
1601 3019 1419 2016
3021 6999 3979 5995
7001 9000 2000 7995
修正:所以我修正了这个问题,在旧版本的MySQL中添加和间隔_start,您可以使用:
select @range_start, min(unit) - 1
from items
where unit >= @range_start
having min(unit) > @range_start
union all
select max(unit) + 1, @range_end
from items
where unit <= @range_end
having max(unit) < @range_end
union all
select unit, unit
from items
union all
select unit + 1, next_unit
from (select i.unit,
(select i2.unit
from items i2
where i2.unit > i.unit
order by i2.unit desc
limit 1
) as next_unit
from items i
) i
where next_unit > unit + 1 and next_unit < @range_end
order by 1;
这是一件很麻烦的事。可以简化工作。有趣的函数是滞后函数还是超前函数,这取决于您想要记录集中的上一个值还是下一个值
这是一个尝试
假设您有如下记录集:
create table test(unit int);
insert test(unit) values (1000);
insert test(unit) values (1040);
insert test(unit) values (1555);
insert test(unit) values (1600);
insert test(unit) values (3020);
insert test(unit) values (7000);
你想要:
+----------------+--------------+----------+---------------------+
| interval_start | interval_end | quantity | quantity_aggregated |
+----------------+--------------+----------+---------------------+
| 1001 | 1039 | 39 | 39 |
| 1041 | 1554 | 514 | 553 |
| 1556 | 1599 | 44 | 597 |
| 1601 | 3019 | 1419 | 2016 |
| 3021 | 6999 | 3979 | 5995 |
| 7001 | 9000 | 2000 | 7995 | additional row showing the end of the range.
+----------------+--------------+----------+---------------------+
结果:
+----------------+--------------+----------+---------------------+
| interval_start | interval_end | quantity | quantity_aggregated |
+----------------+--------------+----------+---------------------+
| 1001 | 1039 | 39 | 39 |
| 1041 | 1554 | 514 | 553 |
| 1556 | 1599 | 44 | 597 |
| 1601 | 3019 | 1419 | 2016 |
| 3021 | 6999 | 3979 | 5995 |
+----------------+--------------+----------+---------------------+
+----------------+--------------+----------+---------------------+
| interval_start | interval_end | quantity | quantity_aggregated |
+----------------+--------------+----------+---------------------+
| 1001 | 1000 | 0 | 0 |
| 1002 | 1000 | -1 | -1 |
| 1002 | 1000 | -1 | -2 |
| 1002 | 1000 | -1 | -3 |
| 1002 | 1000 | -1 | -4 |
+----------------+--------------+----------+---------------------+
interval_start interval_end quantity quantity_aggregated
1001 1039 39 39
1041 1554 514 553
1556 1599 44 597
1601 3019 1419 2016
3021 6999 3979 5995
7001 9000 2000 7995
这应该很容易集成到存储过程中。
注意,我使用了一个子查询来计算运行总和,基于
@最大值用于填充最后一条记录
也许你可以美化这个问题。我不确定是否可以重用带有别名的计算字段,因为平台是Mysql
我不能保证在一个大的记录集上的性能,但不应该比其他记录集差
不确定您的MySQL版本。
如我已经提到的,考虑应用程序中的数据显示问题。code@Strawberry当然,这始终是一个选择:我目前正在这样做。不过,对我来说,在存储过程中封装尽可能多的逻辑更直观。谢谢。但这并不是对特定问题的回答,而是对我之前发表的问题的回答。我改变了场景,我不想包含单独的条目,我只想正确显示这些内容。而且,使用UNION ALL的成本非常高。对不起,我把你弄糊涂了。我会考虑升级到MySQL 8并测试它,但是我不确定升级到MySQL 8是否是个好主意,因为我有一个旧的第三方应用程序2009年,这给我上次MySQL 8带来了一些麻烦。我知道这是一个不同的问题,但有什么想法吗?如果我升级,兼容性问题有多严重?我现在不得不取消将您的回复标记为答案,因为在实施您的解决方案后,我遇到了相反的问题:不是从范围开始。 interval_start interval_end quantity quantity_aggregated 1001 1039 39 39 1041 1554 514 553 1556 1599 44 597 1601 3019 1419 2016 3021 6999 3979 5995 7001 9000 2000 7995