【问题标题】:SQL Server 2005 - Find minimum unused value within a rangeSQL Server 2005 - 查找范围内的最小未使用值
【发布时间】:2013-07-03 01:23:58
【问题描述】:

我有类似以下问题的情况:

Insert Data Into SQL Table

我的方案不同之处在于,我有一个非自动递增的主键字段,其范围可以在 1000 到 1999 之间。到目前为止,我们只有大约一百个值,但最大值已经取了(1999),并且编号顺序存在空白。因此,我需要找到一个介于 1000-1999 之间且未被采用的值。例如,如果我的当前值是 1000、1001、1003 和 1999,我希望查询返回 1002。

【问题讨论】:

    标签: sql sql-server sql-server-2005


    【解决方案1】:

    试试这个:

    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
    

    输出:

    -----------
    3
    
    (1 row(s) affected)
    

    编辑
    这将给出相同的结果:

    ;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
    

    【讨论】:

    • 考虑到这个问题,所有这一切似乎都大量过于复杂。您需要做的就是找到第一个可用的号码,对吗? 交叉连接?
    • 不插入示例的PK值1怎么办? 1 的值是可用的,但它永远不会在第一个查询中返回。
    【解决方案2】:

    我能想到的最简单的方法是创建一个值为 1000-1999 的表,然后执行以下操作:

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

    但其他人可能会想出一个更优雅的解决方案

    【讨论】:

      【解决方案3】:

      编辑:看起来 KM 打败了我……使用他的解决方案。

      我有一个不同的答案,可能比我的另一个更好。

      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
      

      这将找到上面没有其他数字 1 的最小数字。

      【讨论】:

        【解决方案4】:

        不太确定我是否误解了这个问题,但看看类似的东西

        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
        

        结果

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

        您可以从中选择(2 + 1) X-)。

        【讨论】:

          【解决方案5】:

          即使所选范围内没有记录,这也会产生正确答案。这也允许按字段分组以按组获得一组最低值。本例中的 SKU 指的是序号。

          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
          

          distinct 实际上加快了查询速度,即使union 已经执行了distinct。只要你有关于 myType 和 SKU 的索引,它应该是即时的。

          显然,您可以将 0 替换为允许的最低值,将 100 替换为允许的最高值。

          【讨论】:

            【解决方案6】:

            来自 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
            

            【讨论】:

              猜你喜欢
              • 1970-01-01
              • 1970-01-01
              • 2015-10-25
              • 2015-01-11
              • 1970-01-01
              • 2017-08-23
              • 1970-01-01
              • 2019-02-11
              相关资源
              最近更新 更多