开发者

SQL Server 2005 - Find minimum unused value within a range

I have a situation similar to the following question:

Insert Data Into SQL Table

Where my scenario differs is that I have a non-auto-incrementing primary key field that can have a range between 1000 and 1999. We only have about a hundred values in it thus far, but the maximum value has already开发者_运维问答 been taken (1999), and there are gaps in the numbering sequence. Thus, I need to find a value that is between 1000-1999 and not taken. For instance, if my current values are, for example, 1000, 1001, 1003, and 1999, I would want the query to return 1002.


try this:

declare @YourTable table (PK int)
insert @YourTable VALUES (1)
insert @YourTable VALUES (2)
insert @YourTable VALUES (4)
insert @YourTable VALUES (7)
insert @YourTable VALUES (8)


SELECT
    MIN(y.PK)+1
    FROM @YourTable                 y
        LEFT OUTER JOIN @YourTable y2 ON y.PK+1=y2.PK 
    WHERE y.PK>=1 AND y.PK<10 AND y2.PK IS NULL

OUTPUT:

-----------
3

(1 row(s) affected)

EDIT
this will give the same result:

;with N AS 
(SELECT TOP 1000 row_number() over(order by t1.object_id) as Number
     FROM sys.objects t1 
     CROSS JOIN sys.objects t2
)
SELECT
    MIN(Number) AS PK
    FROM N
        LEFT OUTER JOIN @YourTable y on n.Number=y.PK
    WHERE y.PK IS Null


The simplest way I can think of is to create a table with values 1000-1999 then do the following:

Select MIN(Values.Key)
From Main
Left Join Values on Values.Key = Main.Key
Where Main.Key is Null

But someone else can probably come up with a more elegant solution


EDIT: Looks like KM Beat me to it... use his solution.

I have a different answer that may be better than my other one.

Select Min(Main1.Key)+1
From Main as Main1
Left Join Main as Main2 on Main1.Key+1=Main2.Key
Where Main2.Key is Null

This will find the lowest number that doesn't have another number 1 above it.


Not quite sure if I misunderstood the question but have a look at something like

declare @YourTable table (PK int) 
insert @YourTable VALUES (1) 
insert @YourTable VALUES (2) 
insert @YourTable VALUES (4) 
insert @YourTable VALUES (7) 
insert @YourTable VALUES (8) 

SELECT  TOP 1
        *
FROM    @YourTable yt
WHERE   NOT EXISTS  (
                        SELECT  1 
                        FROM    @YourTable 
                        WHERE   yt.PK+1 = PK
                    )
ORDER BY yt.PK

Results in

PK
-----------
2

From where you can pick (2 + 1) X-).


This produces a correct answer even if there are no records within the selected range. This also allows grouping by a field to get a set of lowest values by group. SKU in this example refers to the sequential numbers.

SELECT    A.myType, 
          COALESCE (MIN( A.sku) + 1, 1) AS SKU /* 1 is Min Default + 1 */
FROM      (  SELECT  distinct myType, sku
             FROM    dbo.myTable AS p1
             where   p1.sku > 0       /* zero is Min Value */ 
                     and p1.sku < 100 /* 100 is Max Value */ 
             union 
             select  distinct myType, 0 as sku /* Guarantee Min Value */
             from    dbo.myTable as t1
          ) AS A 
          LEFT OUTER JOIN
          (  SELECT distinct myType, sku
             FROM   dbo.myTable AS p2
             where  p2.sku > 0         /* zero is Min Value */ 
                    and p2.sku < 100   /* 100 is Max Value */
             union 
             select distinct myType, 0 as sku  /* Guarantee Min Value */
             from   dbo.myTable as t2
          ) AS B 
          ON A.myType = B.myType AND 
             A.sku + 1 = B.sku
where     (B.sku IS NULL)
GROUP BY  A.myType

The distinct actually speeds up the query even though union already does a distinct. As long as you have an index on myType and SKU, it should be instant.

Obviously, you can replace 0 with the lowest and 100 with the highest allowed values.


from How do I find a "gap" in running counter with SQL?

select
    MIN(ID)
from (
    select
        1000 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
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜