在MySQL中查找顺序值之间的间隙

在MySQL中查找顺序值之间的间隙,mysql,sql,Mysql,Sql,更新2:我已经解决了最初的两个问题。但当我做了建议滚动更新的更改时,另一个出现了 我使用MySQL 5.7。更新:现在迁移到MySQL 8.0 我有这张桌子: +------+ | unit | +------+ | 1000 | | 1040 | | 1555 | | 1600 | | 3020 | | 7000 | +------+ +-------------+ | unit | +-------------+ | 3079 | | 3130 |

更新2:我已经解决了最初的两个问题。但当我做了建议滚动更新的更改时,另一个出现了

我使用MySQL 5.7。更新:现在迁移到MySQL 8.0

我有这张桌子:

+------+
| 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