Ответ 1
select ID +1 From Table t1
where not exists (select * from Table t2 where t1.id +1 = t2.id);
не уверен, что эта версия будет быстрее, чем предыдущая.
Недавно я унаследовал базу данных, на которой одна из таблиц имеет первичный ключ, состоящий из закодированных значений (Part1 * 1000 + Part2).
Я нормализовал этот столбец, но я не могу изменить старые значения.
Итак, теперь у меня
select ID from table order by ID
ID
100001
100002
101001
...
Я хочу найти "дыры" в таблице (точнее, первое "отверстие" после 100000) для новых строк.
Я использую следующий выбор, но есть ли лучший способ сделать это?
select /* top 1 */ ID+1 as newID from table
where ID > 100000 and
ID + 1 not in (select ID from table)
order by ID
newID
100003
101029
...
База данных - это Microsoft SQL Server 2000. Я в порядке с использованием расширений SQL.
select ID +1 From Table t1
where not exists (select * from Table t2 where t1.id +1 = t2.id);
не уверен, что эта версия будет быстрее, чем предыдущая.
SELECT (ID+1) FROM table AS t1
LEFT JOIN table as t2
ON t1.ID+1 = t2.ID
WHERE t2.ID IS NULL
Это решение должно дать вам первое и последнее значение идентификатора "дыр", которые вы ищете. Я использую это в Firebird 1.5 на таблице 500K записей, и хотя это занимает немного времени, оно дает мне то, что я хочу.
SELECT l.id + 1 start_id, MIN(fr.id) - 1 stop_id
FROM (table l
LEFT JOIN table r
ON l.id = r.id - 1)
LEFT JOIN table fr
ON l.id < fr.id
WHERE r.id IS NULL AND fr.id IS NOT NULL
GROUP BY l.id, r.id
Например, если ваши данные выглядят следующим образом:
ID
1001
1002
1005
1006
1007
1009
1011
Вы получили бы это:
start_id stop_id
1003 1004
1008 1008
1010 1010
Хотелось бы, чтобы я смог полностью оценить это решение, но нашел его в Xaprb.
Лучший способ - создать временную таблицу со всеми идентификаторами
Затем сделайте левое соединение.
declare @maxId int
select @maxId = max(YOUR_COLUMN_ID) from YOUR_TABLE_HERE
declare @t table (id int)
declare @i int
set @i = 1
while @i <= @maxId
begin
insert into @t values (@i)
set @i = @i +1
end
select t.id
from @t t
left join YOUR_TABLE_HERE x on x.YOUR_COLUMN_ID = t.id
where x.YOUR_COLUMN_ID is null
Недавно подумал об этом вопросе и выглядит так: это самый элегантный способ сделать это:
SELECT TOP(@MaxNumber) ROW_NUMBER() OVER (ORDER BY t1.number)
FROM master..spt_values t1 CROSS JOIN master..spt_values t2
EXCEPT
SELECT Id FROM <your_table>
Это решение не дает всех отверстий в таблице, только следующие бесплатные - + первое доступное максимальное число в таблице - работает, если вы хотите заполнить пробелы в id-es, + получить бесплатный номер id, если у вас нет разрыв..
выберите numb + 1 из temp минус выберите numb from temp;
from Как найти "пробел" ? в запуске счетчика с SQL?
select
MIN(ID)
from (
select
100001 ID
union all
select
[YourIdColumn]+1
from
[YourTable]
where
--Filter the rest of your key--
) foo
left join
[YourTable]
on [YourIdColumn]=ID
and --Filter the rest of your key--
where
[YourIdColumn] is null
Это даст вам полное изображение, где "Нижний" обозначает задержка пробела и "Верх" означает пробел конец
select *
from
(
(select <COL>+1 as id, 'Bottom' AS 'Pos' from <TABLENAME> /*where <CONDITION*/>
except
select <COL>, 'Bottom' AS 'Pos' from <TABLENAME> /*where <CONDITION>*/)
union
(select <COL>-1 as id, 'Top' AS 'Pos' from <TABLENAME> /*where <CONDITION>*/
except
select <COL>, 'Top' AS 'Pos' from <TABLENAME> /*where <CONDITION>*/)
) t
order by t.id, t.Pos
Примечание. Первые и Последние результаты WRONG, и их не следует рассматривать, но их вывод сделает этот запрос намного сложнее, так что теперь это будет делать.
Многие из предыдущих ответов довольно хороши. Однако все они пропускают, чтобы вернуть первое значение последовательности и/или пропустить, чтобы рассмотреть нижний предел 100000. Все они возвращают промежуточные отверстия, но не самые первые (100001, если они отсутствуют).
Полное решение вопроса следующее:
select id + 1 as newid from
(select 100000 as id union select id from tbl) t
where (id + 1 not in (select id from tbl)) and
(id >= 100000)
order by id
limit 1;
Число 100000 должно использоваться, если первый номер последовательности равен 100001 (как в исходном вопросе); в противном случае оно должно быть соответствующим образом изменено "limit 1" используется для того, чтобы иметь только первое доступное число вместо полной последовательности
Для людей, использующих Oracle, можно использовать следующее:
select a, b from (
select ID + 1 a, max(ID) over (order by ID rows between current row and 1 following) - 1 b from MY_TABLE
) where a <= b order by a desc;