Это сложный вариант проблемы пробелов и островов, поскольку:
- вам нужны все элементы в группе (не только начало и конец)
- вам нужны только элементы первой группы, удовлетворяющие условию
Следующий запрос выполняет то, что вы ожидаете:
select lotNumber
from (
select
lotNumber,
cnt,
dense_rank() over(order by grp) rn
from (
select
lotNumber,
grp,
count(*) over(partition by grp) cnt
from (
select
lotNumber,
sum(case when lotNumber = lagLotNumber - 1 then 0 else 1 end)
over(order by id) grp
from (
select
id,
lotNumber,
lag(lotNumber) over(order by id) lagLotNumber
from mytable
) t
) t
) t
where cnt >= 3
) t
where rn = 1
Предложение where cnt >= 3
можно использовать для управления цельюдлина последовательных чисел.
Демонстрация на DB Fiddle
| lotnumber |
| --------- |
| 95090 |
| 95089 |
| 95088 |
Пошаговые пояснения
Для начала, это может быть решено только , если существует столбец, который можно использовать для упорядочения записей (в таблицах sql записи по умолчанию неупорядочены). Я предполагаю, что такой столбец существует и называется id
. Вот набор данных:
| lotnumber | id |
| --------- | --- |
| 1065 | 1 |
| 1026 | 2 |
| 95092 | 3 |
| 95090 | 4 |
| 95089 | 5 |
| 95088 | 6 |
| 85087 | 7 |
| 95086 | 8 |
| 95085 | 9 |
| 95084 | 10 |
| 95083 | 11 |
| 95082 | 12 |
| 95081 | 13 |
1) Первый шаг состоит в восстановлении предыдущих lotNumber
каждой записи. Для этого мы используем lag()
.
select
id,
lotNumber,
lag(lotNumber) over(order by id) lagLotNumber
from mytable
| id | lotnumber | laglotnumber |
| --- | --------- | ------------ |
| 1 | 1065 | |
| 2 | 1026 | 1065 |
| 3 | 95092 | 1026 |
| 4 | 95090 | 95092 |
...
2) Затем мы используем накопленную сумму для помещения записей в группы, где номера лотов являются последовательными. Когда две записи не являются последовательными, начинается новая группа:
select
lotNumber,
sum(case when lotNumber = lagLotNumber - 1 then 0 else 1 end)
over(order by id) grp
from (
... above query ...
) t
| lotnumber | grp |
| --------- | --- |
| 1065 | 1 |
| 1026 | 2 |
| 95092 | 3 |
| 95090 | 4 |
| 95089 | 4 |
| 95088 | 4 |
| 85087 | 5 |
| 95086 | 6 |
| 95085 | 6 |
| 95084 | 6 |
| 95083 | 6 |
| 95082 | 6 |
| 95081 | 6 |
3) Следующий шаг состоит в подсчете количества записей в каждой группе с количеством окон
select
lotNumber,
grp,
count(*) over(partition by grp) cnt
from (
... above query ...
) t;
| lotnumber | grp | cnt |
| --------- | --- | --- |
| 1065 | 1 | 1 |
| 1026 | 2 | 1 |
| 95092 | 3 | 1 |
| 95090 | 4 | 3 |
| 95089 | 4 | 3 |
| 95088 | 4 | 3 |
| 85087 | 5 | 1 |
| 95086 | 6 | 6 |
| 95085 | 6 | 6 |
| 95084 | 6 | 6 |
| 95083 | 6 | 6 |
| 95082 | 6 | 6 |
| 95081 | 6 | 6 |
4) Имея эту информацию под рукой, мы можем теперь фильтровать группы, которые имеют как минимум целевое количество последовательных записей. В то же время мы ранжируем группы по возрастанию номера лота. Условие фильтрации where cnt >= 3
может быть изменено по мере необходимости для управления целевым числом последовательных записей.
Здесь у нас есть две группы по крайней мере с 3 последовательными числами:
select
lotNumber,
cnt,
dense_rank() over(order by grp) rn
from (
... above query ...
) t
where cnt >= 3;
| lotnumber | cnt | rn |
| --------- | --- | --- |
| 95090 | 3 | 1 |
| 95089 | 3 | 1 |
| 95088 | 3 | 1 |
| 95086 | 6 | 2 |
| 95085 | 6 | 2 |
| 95084 | 6 | 2 |
| 95083 | 6 | 2 |
| 95082 | 6 | 2 |
| 95081 | 6 | 2 |
5)Последний шаг заключается в фильтрации первой записи в каждой группе.
select lotNumber
from (
... above query ...
) t
where rn = 1
| lotnumber |
| --------- |
| 95090 |
| 95089 |
| 95088 |