Страницы 1
Дано: таблица. Количество полей не важно, важно то, что в ней есть одно поле (пусть будет id, integer). Оно же ключевое, без автоприращения.
Необходимо: SQL-запрос, который находит первое пустое значение.
Пример: в поле содержатся значения 2, 3, 4, 7. Запрос должен выдать 1. В поле содержатся значения 1, 2, 3, 4, 7. Запрос должен выдать 5.
Неактивен
Неактивен
хотя это и неважно :-)
важно, и синтаксис запросов и, особенно, написание сторед процедур различаются.
Различные варианты поставленной задачи для MS SQL:
https://stackoverflow.com/questions/6841 … -in-ms-sql
Хотелось бы обратить внимание на один из комментов:
However, the policy you're describing is really not a good idea. ID values should be unique, but should not be required to be consecutive.
What happens if you email someone with a link to document #42, and then subsequently delete the document? Later, you re-use the id #42 for a new document. Now the recipient of the email will follow the link to the wrong document!
Я сильно поддерживаю того, кто это написал. Хотя, может, именно такое поведение тебе и нужно. Фиг знает.
Квантовая механика - "малопонятный математический курьёз" (с) msAVA - современный учитель.
Неактивен
Хотя, может, именно такое поведение тебе и нужно. Фиг знает.
Мне было интересно, представит ли кто-нибудь 1 (один) запрос хоть под какой-нибудь сервер. Супер-мега-кул-программеров с миллиоами пользователей их творений на форуме хватает, а на простой вопрос ответа нету :-(
Неактивен
Неактивен
Там их 16.
Именно что там. В MSDN их ещё больше. :-)
Необходимо: SQL-запрос, который находит первое пустое значение.
И, кстати, как отреагируют те запросы при
в поле содержатся значения 2, 3, 4, 7. Запрос должен выдать 1
А если 2, 7, 3, 4? Или 7, 2, 3,4.
Кстати, условие написал не совсем верно. Не первое, а минимальное значение.
Редактировался Maddoc (06-11-10 02:34:28)
Неактивен
Именно что там. В MSDN их ещё больше. :-)
Ну тогда это глупо, как и что ты написал тут. Сам поймешь или объяснить?
А если 2, 7, 3, 4? Или 7, 2, 3,4.
Первый же вариант решения с MS SQL подходит и под этот случай
Не первое, а минимальное значение.
Это тебе задачку в институт что ле решить надо?
А то с каждой допиской она становится более и более бредовой.
Добавлено спустя 8 ч 21 мин 01 с:
Maddoc, см лс
Квантовая механика - "малопонятный математический курьёз" (с) msAVA - современный учитель.
Неактивен
select rnum as "пропущенное зн-е" from (select rownum as rnum, id from testid order by id) where rnum != id;
Не вернет 4, если у тебя ид будут 1 2 3 тк.к. всегда ровнам будет равен ид. Как я понял в задаче надо, чтобы в таком случае возвращалось 4.
В принципе мы еще один вариант подробно разобрали в ЛС. Если мэдок одобрит, сюда выложу.
Квантовая механика - "малопонятный математический курьёз" (с) msAVA - современный учитель.
Неактивен
первое пустое значение ... Кстати, условие написал не совсем верно. Не первое, а минимальное значение.
если индекс больше нуля и записаны 1 2 3 - следующее пустое значение будет 4. Ну и в личке мне мэддок чуть больше объяснил зачем это. Как я понял должно быть 4.
Квантовая механика - "малопонятный математический курьёз" (с) msAVA - современный учитель.
Неактивен
Неактивен
чесгря, удивительно, что так никто и не придумал такой запрос
а я придумал, хотя спецом по sql себя совершенно не считаю.
вот:
SELECT MIN(maxprev+1) FROM
(
SELECT mainid, MAX(previd) as maxprev, mainid-maxprev as diff FROM
(SELECT table1.id as mainid , table2.id as previd
FROM Table1, table1 as table2)
WHERE mainid > previd GROUP BY mainid
)
WHERE diff > 1
за быстродействие и вообще оптимальность, впрочем, не поручусь.
"Фу бля, крохобор вонючий" (с) Svart Testare
Неактивен
за быстродействие и вообще оптимальность, впрочем, не поручусь.
А если цифры 5 6 7, то какое значение запрос выдаст?
В ссылке, которая приведена во втором сообщении, первый запрос как раз, по сути, этот. Только скан делает по i+1
чесгря, удивительно, что так никто и не придумал такой запрос
06-11-10 14:07:11
В принципе мы еще один вариант подробно разобрали в ЛС. Если мэдок одобрит, сюда выложу.
Просто мэдок бухает, поэтому не опубликовано.
Квантовая механика - "малопонятный математический курьёз" (с) msAVA - современный учитель.
Неактивен
А если цифры 5 6 7, то какое значение запрос выдаст?
ыыыы. это не учитывается, да.
"Фу бля, крохобор вонючий" (с) Svart Testare
Неактивен
Ну, вобщем, раз меддок бухает, то выложу что ле.
Решение без дурацких запросов: Дефрагментация индексов.
https://msdn.microsoft.com/en-us/library/ff650692.aspx
Решение с дурацким запросом:
Идея в том же поиске по ид+1. Фишка в чем, поиск с ид+1 катит, но не учитывает первые пустые поля (если числа. например 567). Для этого можно делать одну проверку на занятость ячейки с с ид=1. Если такая ячейка не занята, то сначала надо занять ее (минимальный, да). Если занята от нее уже само отсчитывается.
SELECT TOP (1) CASE
WHEN (NOT EXISTS (SELECT id FROM test AS t2 WHERE (t2.id = 1))) THEN 1
WHEN (NOT EXISTS (SELECT id FROM test AS t2 WHERE (id = t1.id + 1))) THEN id + 1
END AS 'freeId'
FROM test AS t1
ORDER BY id
С точки зрения быстродействия, если есть ордер бай, МС БД может в любом случае перебирать таблицу от начала до конца (до поиска дырок). Чтобы этого избежать можно использовать кластеред индексы. Тогда ордер бай идет по ним и, по идее, перебор будет идти только до дырки (топ(1) остаовит).
https://technet.microsoft.com/en-us/libr … 90639.aspx
Если верить описанию оптимайзера МС ДБ, NOT EXISTS (SELECT id FROM test AS t2 WHERE (t2.id = 1)) будет проверена 1 раз.
Таким образом первый кейс проверяет только первый же индекс. Второй кейс перебирает до первой дырки. Поэтому это, наверное, оптимально с точки зрения быстродействия. Но это в теории. На практике - я не специалист по МС БД. Профайлер в руки и смотреть))
Можно эту логику - проверить 1-й, искать с ид+1 реализовать просто с помощью IF, ELSE в запросе и не надеяться на правильную оптимизацию. Можно записать в виде 2-х запросов с юнион. 1-й из которых возвращает 1 или нуль. Будет ли быстрее работать на практике? - без понятия, не специалист.
Решение с ров набмером:
ROW_NUMBER() не возвращает 4, если у тебя числа 1 2 3. Значит можно добавлять такой же(как в прошлом примере) проверочный запрос, только проверять последнее поле, а отсчитывать последнее поле по логике больнее, чем первое. К тому же МС СКЛ ROW_NUMBER() идет со своим сорт бай и, возможно, будет перелопачивать таблицу даже с кластеред индексами
Ссылка на проблему медленного ROW_NUMBER
https://weblogs.asp.net/eporter/archive/ … t-Set.aspx
Более дурацкие решения, которые рождались в процессе:
SELECT TOP (1) id - 1 AS freeId FROM test AS t1
WHERE (NOT EXISTS
(SELECT id
FROM test AS t2
WHERE (id = t1.id - 1))) AND (id - 1 > 0)
UNION
SELECT id + 1 AS freeId FROM test AS t1
WHERE NOT EXISTS
(SELECT id
FROM test AS t2
WHERE (id = t1.id + 1))
ORDER BY freeId
Например, если у тебя числа 5 6 8, этим запросом ты получишь 4 7 9. Т.е. если ты будешь брать первое значение этого запроса, ты будешь сначала заселять пустые места "к началу", а только потом все остальные. Будет ли такой запрос хорошо оптимизироваться по TOP(1) - не имею понятия, но предполагаю, что первое решение - лучше)))
Более громоздкие решения
Можно делать карты дырок, например, но к чему этот гемор?
Прицепить триггеры на инсерт и делет, которые будут вписывать и убирать "карту".
Квантовая механика - "малопонятный математический курьёз" (с) msAVA - современный учитель.
Неактивен
Страницы 1