[ Поиск ] - [ Пользователи ] - [ Календарь ]
Полная Версия: Поиск пропущенных чисел в таблице
Страницы: 1, 2, 3
sergeiss
Иногда у программера появляется задача определить, какие из чисел в таблице пропущены. Это могут айдишники, это могут быть другие числа - не суть важно.

Вообще, такая тема возникла недавно вот тут http://phpforum.ru/index.php?showtopic=82503&hl= Я в итоге что-то сваял, а затем подумал, что пропадёт ведь. На 3-й странице уже не так заметно. А полезно может быть кому-нибудь.

Да, в интернете предлагаются какие-то решения, но чаще всего с использованием некой "опорной" таблицы, где заведомо есть все числа из заданного диапазона.

Мои решения отличаются тем, что им не нужна никакая другая таблица, я работаю только с той таблицей, в которой идет поиск инфы.

1. Решение для Постгре. Тут предполагается, что мы ищем данные среди всех имеющихся чисел.
Свернутый текст
with
ini_sel as
(
select e1.id as id1 , e1.id-1 as id_to, e2.id as id_from
from enums e1
full join
(select id+1 as id
from enums) e2
using( id )
where e1.id is null or e2.id is null
),
lost as
(
select * from
(
select id_to as id, 2::integer as bound from ini_sel
union
select
id_from, 1 from ini_sel
) sec_sel
where id is not null and id between (select min(id) from enums) and (select max(id) from enums)
)



select id_from, id_to,
case when id_from = id_to then
id_from::varchar
else
id_from || '-' || id_to
end as range

from
(
select id as id_from, (select id from lost where id>=ext_lost.id and bound=2 limit 1) as id_to
from lost ext_lost

where bound=1
) lost_list


Пример результата, выдаваемого этим запросом:
Свернутый текст
id_from id_to range
3 3 3
10 11 10-11
13 14 13-14
16 23 16-23

Первая колонка показывает начало диапазона отсутствующих чисел, вторая колонка - конец диапазона. Третья колонка - это число или диапазон.


2. Решение для Мускуля. В данном коде было заранее известно, что искомые числа лежат в диапазоне от 2 до 14, включая границы диапазона.

Свернутый текст
select id_from as id, 1 as boundary
from
(
select id+1 as id_from

from
(select id from tab3 id where id between 1 and 15 ) t1
left join
(select id-1 as id2 from tab3 where id between 1 and 15) t2
on t1.id = t2.id2
where id2 is null and id < 14) id_min
where id_from between 2 and 14

union

select
id_to, 2
from
(
select id-1 as id_to
from
(select id from tab3 id where id between 1 and 15 ) t1
left join
(select id+1 as id2 from tab3 where id between 1 and 15) t2
on t1.id = t2.id2
where id2 is null and id < 15) id_max
where id_to between 2 and 14

order by id, boundary


Пример результата для Мускуля:
Свернутый текст
id boundary
4 1
4 2
7 1
7 2
9 1
13 2

Здесь 1 и 2 во второй колонке показывают, что это начало диапазона (1) или конец диапазона (2). В данном примере это числа 4, 7 и от 9 до 13.

Решение можно привести к тому же виду, что и решение для Постгре.

_____________
* Хэлп по PHP
* Описалово по JavaScript
* Хэлп и СУБД для PostgreSQL

* Обучаю PHP, JS, вёрстке. Интерактивно и качественно. За разумные деньги.

* "накапливаю умение телепатии" (С) и "гуглю за ваш счет" (С)

user posted image
Быстрый ответ:

 Графические смайлики |  Показывать подпись
Здесь расположена полная версия этой страницы.
Invision Power Board © 2001-2025 Invision Power Services, Inc.