Как найти пропущенное число в поле таблицы, начиная с параметра и последовательно увеличивая его? - PullRequest
2 голосов
/ 26 октября 2010

Допустим, у меня есть таблица сервера sql:

NumberTaken CompanyName

2 Фред3 Фред4 Фред6 Фред7 Фред8 Фред11 Фред

Мне нужен эффективный способ передачи параметра [StartingNumber] и последовательного отсчета от [StartingNumber], пока я не найду пропущенное число.

Например, обратите внимание, что 1, 5,9 и 10 отсутствуют в таблице.

Если бы я указал параметр [StartingNumber] = 1, он проверил бы, существует ли 1, если он это сделает, то проверит, существует ли 2 и т. Д., Ии так далее, здесь будет возвращено 1.

Если [StartNumber] = 6, функция вернет 9.

В псевдокоде c # это будет в основном:

int ctr = [StartingNumber]
while([SELECT NumberTaken FROM tblNumbers Where NumberTaken = ctr] != null)    
    ctr++;

return ctr;

Проблема с этим кодом в том, что он кажется действительно неэффективным, если в таблице тысячи чисел.Кроме того, я могу написать его в коде C # или в хранимой процедуре, в зависимости от того, что более эффективно.

Спасибо за помощь

Ответы [ 4 ]

2 голосов
/ 26 октября 2010

Решение с использованием JOIN:

select min(r1.NumberTaken) + 1
from MyTable r1
left outer join MyTable r2 on r2.NumberTaken = r1.NumberTaken + 1
where r1.NumberTaken >= 1 --your starting number
    and r2.NumberTaken is null
1 голос
/ 27 октября 2010

Я назвал свою таблицу пустым и использовал следующее:

declare @StartOffset int = 2
; With Missing as (
    select @StartOffset as N where not exists(select * from Blank where ID = @StartOffset)
), Sequence as (
    select @StartOffset as N from Blank where ID = @StartOffset
    union all
    select b.ID from Blank b inner join Sequence s on b.ID = s.N + 1
)
select COALESCE((select N from Missing),(select MAX(N)+1 from Sequence))

У вас в основном есть два случая - либо отсутствует ваше начальное значение (поэтому Missing CTE будет содержать одну строку), либо оно присутствует,таким образом, вы рассчитываете вперед, используя рекурсивный CTE (последовательность), берете из этого максимум и добавляете 1

Edit из комментария.Да, создайте еще один CTE в верхней части, который соответствует критериям вашего фильтра, а затем используйте его в остальной части запроса:

declare @StartOffset int = 2
; With BlankFilters as (
    select ID from Blank where hasEntered <> 1
), Missing as (
    select @StartOffset as N where not exists(select * from BlankFilters where ID = @StartOffset)
), Sequence as (
    select @StartOffset as N from BlankFilters where ID = @StartOffset
    union all
    select b.ID from BlankFilters b inner join Sequence s on b.ID = s.N + 1
)
select COALESCE((select N from Missing),(select MAX(N)+1 from Sequence))

теперь это может вернуть строку, которая существует в таблице, но hasEntered = 1

Таблицы:

create table Blank (
    ID int not null,
    Name varchar(20) not null
)
insert into Blank(ID,Name)
select 2 ,'Fred' union all
select 3 ,'Fred' union all
select 4 ,'Fred' union all
select 6  ,'Fred' union all
select 7 ,'Fred' union all
select 8 ,'Fred' union all
select 11 ,'Fred'
go
0 голосов
/ 27 октября 2010

Создайте временную таблицу со всеми числами от StartingValue до EndValue и LEFT OUTER JOIN к вашей таблице данных.

0 голосов
/ 26 октября 2010

Попробуйте подход, основанный на множестве - должен быть быстрее

select min(t1.NumberTaken)+1 as "min_missing" from t t1
where not exists (select 1 from t t2 
                   where t1.NumberTaken = t2.NumberTaken+1)
and t1.NumberTaken > @StartingNumber

Это синтаксис Sybase, так что при необходимости используйте SQL Server.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...