#sql #sqlite
#sql #sqlite
Вопрос:
Предполагается, что у вас есть таблица T(A)
, в которой разрешены только положительные целые числа, например:
1,1,2,3,4,5,6,7,8,9,11,12,13,14,15,16,17,18
В приведенном выше примере результатом является 10
. Мы всегда можем использовать ORDER BY
и DISTINCT
для сортировки и удаления дубликатов. Однако, чтобы найти наименьшее целое число, которого нет в списке, я придумал следующий SQL
запрос:
select list.x 1
from (select x from (select distinct a as x from T order by a)) as list, T
where list.x 1 not in T limit 1;
Моя идея заключается в том, чтобы запустить a counter
и 1, проверить, находится ли этот счетчик в list
: если это так, верните его, в противном случае увеличьте и посмотрите снова. Однако я должен запустить этот счетчик как 1, а затем увеличить. Этот запрос работает в большинстве случаев, поскольку есть несколько угловых случаев, таких как в 1
. Как я могу добиться этого в SQL
или я должен пойти в совершенно другом направлении, чтобы решить эту проблему?
Комментарии:
1. @MarcAudet: Я думаю, требуется вернуть 10.
2. @MarcAudet Я бы ожидал значение
2
в упомянутом угловом регистре. Для первого примера я ожидаю10
от имени Jonathan.3. Я отредактировал вопрос, чтобы показать, что
10
это действительно ожидаемый результат для этого примера. @JonathanLeffler4. @Mihai: теги? PostegresSQL, MySQL и SQL Server?
5. Я бы сгенерировал таблицу, в которой целые числа варьируются от (min, max 1), объединил правой кнопкой мыши в этой таблице и выбрал min (число), где нет совпадения, но генерация диапазона целых чисел отличается от базы данных к базе данных
Ответ №1:
Поскольку SQL работает с наборами, промежуточное значение SELECT DISTINCT a AS x FROM t ORDER BY a
является избыточным.
Основной метод поиска разрыва в столбце целых чисел заключается в том, чтобы найти место, где текущая запись плюс 1 не существует. Для этого требуется какое-то самосоединение.
Ваш запрос не за горами, но я думаю, его можно упростить до:
SELECT MIN(a) 1
FROM t
WHERE a 1 NOT IN (SELECT a FROM t)
Значение NOT IN действует как своего рода самосоединение. Это ничего не создаст из пустой таблицы, но в противном случае должно быть нормально.
Ответ №2:
select min(y.a) as a
from
t x
right join
(
select a 1 as a from t
union
select 1
) y on y.a = x.a
where x.a is null
Это будет работать даже в пустой таблице
Ответ №3:
SELECT min(t.a) - 1
FROM t
LEFT JOIN t t1 ON t1.a = t.a - 1
WHERE t1.a IS NULL
AND t.a > 1; -- exclude 0
Это находит наименьшее число, большее 1, где следующее меньшее число отсутствует в той же таблице. Возвращается это отсутствующее число.
Это работает даже для отсутствующего 1. Есть несколько ответов, проверяющих в противоположном направлении. Все они завершились бы ошибкой с отсутствующим 1.
Ответ №4:
Вы можете сделать следующее, хотя вы также можете захотеть определить диапазон — в этом случае вам может понадобиться пара объединений
SELECT x.id 1
FROM my_table x
LEFT
JOIN my_table y
ON x.id 1 = y.id
WHERE y.id IS NULL
ORDER
BY x.id LIMIT 1;
Комментарии:
1. как насчет пустой таблицы?
2. Ваш запрос не работает для
2,3,5,7,9,11,13,15,17,19
3. @JonathanLeffler Предлагаемая таблица чисел с левым соединением также подойдет для пустой таблицы.
4. Как я уже сказал, при определенных обстоятельствах вам может потребоваться ОБЪЕДИНЕНИЕ дополнительно
Ответ №5:
Вы всегда можете создать таблицу со всеми числами от 1 до X, а затем объединить эту таблицу с таблицей, которую вы сравниваете. Затем просто найдите в своем операторе SELECT верхнее значение, которого нет в таблице, которую вы сравниваете
SELECT TOP 1 table_with_all_numbers.number, table_with_missing_numbers.number
FROM table_with_all_numbers
LEFT JOIN table_with_missing_numbers
ON table_with_missing_numbers.number = table_with_all_numbers.number
WHERE table_with_missing_numbers.number IS NULL
ORDER BY table_with_all_numbers.number ASC;
Комментарии:
1. У @ CL OP этот вопрос был помечен как SQL Server, но я предполагаю, что он изменил его
Ответ №6:
В SQLite 3.8.3 или более поздней версии вы можете использовать рекурсивное общее табличное выражение для создания счетчика. Здесь мы прекращаем подсчет, когда находим значение, которого нет в таблице:
WITH RECURSIVE counter(c) AS (
SELECT 1
UNION ALL
SELECT c 1 FROM counter WHERE c IN t)
SELECT max(c) FROM counter;
(Это работает для пустой таблицы или отсутствующего 1
.)
Ответ №7:
Этот запрос ранжирует (начиная с ранга 1) каждое отдельное число в порядке возрастания и выбирает наименьший ранг, который меньше его номера. Если ранг не ниже его номера (т. Е. в таблице нет пробелов), запрос возвращает максимальное число 1.
select coalesce(min(number),1) from (
select min(cnt) number
from (
select
number,
(select count(*) from (select distinct number from numbers) b where b.number <= a.number) as cnt
from (select distinct number from numbers) a
) t1 where number > cnt
union
select max(number) 1 number from numbers
) t1
Ответ №8:
Просто другой метод, использующий, ЗА исключением этого времени:
SELECT a 1 AS missing FROM T
EXCEPT
SELECT a FROM T
ORDER BY missing
LIMIT 1;