选择范围内的最小数字

问题描述 投票:0回答:3

我有一个包含类似数据的表格。

ItemCode
1000
1002
1003
1020
1060

我正在尝试编写一条 SQL 语句来获取不在该表中的最小编号(ItemCode),并且一旦将前一个最小订单 ID 插入表中,它应该能够获取下一个最小编号,但也可以跳过数据库中已有的数字。我只想在每次运行查询时获得 1 个结果。

因此,根据上表,它应该得到

1001
作为第一个结果。一旦
ItemCode = 1001
被插入到表中,它应该得到的下一个结果应该是
1004
,因为
1000
1003
已经存在于表中。

根据我在网上看到的所有内容,我认为我必须使用 While 循环来执行此操作。这是我仍在研究的代码。

DECLARE @Count int
SET @Count= 0   
WHILE Exists (Select ItemCode
                from OITM
                where itemCode like '10%'
                AND convert(int,ItemCode) >= '1000'
                and convert(int,ItemCode) <= '1060')
        Begin
            SET @COUNT = @COUNT + 1

            select MIN(ItemCode) + @Count
            from OITM
            where itemCode like '10%'
            AND convert(int,ItemCode) >= '1000'
            and convert(int,ItemCode) <= '1060'
        END

我觉得必须有一种更简单的方法来实现这一点。有什么办法让我说...

选择表 X 中不存在的 1000 到 1060 之间的最小数字

编辑:在我的情况下创建新表不是一个选项

最终编辑:谢谢大家!我得到了它。这是我的最终查询,它返回了我想要的结果。我知道我无缘无故地把事情搞得太复杂了!

With T0 as ( select convert(int,ItemCode) + row_number() over (order by convert(int,ItemCode)) as ItemCode
             from OITM
             where itemCode like '10%'
             AND convert(int,ItemCode) >= '1000'
             And convert(int,ItemCode) <= '1060')
Select MIN(convert(varchar,ItemCode)) as ItemCode
from T0
where convert(int,ItemCode) Not in (Select convert(int,ItemCode)
                                    from OITM
                                    where itemCode like '10%'
                                    AND convert(int,ItemCode) >= '1000'
                                    and convert(int,ItemCode) <= '1060');
sql sql-server rdbms
3个回答
2
投票

这应该可以解决问题。在这里,您为行生成序号,然后将每一行与下一行进行比较(通过连接条件完成),并仅过滤差异不为 1 的行,按顺序排序,最后选择最上面的。

;with c as(select id, row_number() over(order by id) rn)
select top 1 c1.id + 1 as NewID
from c as c1
join c as c2 on c1.rn + 1 = c2.rn
where c2.id - c1.id <> 1
order by c1.rn

2
投票

您可以使用

row_number()
为每行生成连续值,然后查找
row_number()
与表中存储的值不匹配的第一行。我的 SQL Server 安装目前无法正常工作,并且 SQL Fiddle 似乎也出现故障,所以我写了这篇文章但无法测试它,但类似这样的东西应该可以工作:

declare @lowerBound int = 1000;
declare @upperBound int = 1060;

declare @x table ([id] int);
insert @x values (1000), (1002), (1003), (1020), (1060);

with [SequenceCTE] as
(
    select
        [id],
        [seq] = (@lowerBound - 1) + row_number() over (order by [id])
    from
        @x
)
select top 1
    [seq]
from
    [SequenceCTE]
where
    [seq] != [id] and
    [seq] <= @upperBound;
    

编辑:Here是演示这种方法的 SQL Fiddle。我不知道为什么该网站以前不适合我。由于某种原因,它似乎不喜欢我的

declare
语句,因此我对边界进行了硬编码,但希望它仍然能传达这个想法。


1
投票

您可以使用计数表来完成此操作。查看 Jeff Moden 的这篇文章以供参考。

基本上,您想要生成从

@start
@end
的数字。这就是计数表的用武之地。它将用于数字生成。当您获得数字后,您只需检查表中不存在的最小值即可。

SQL 小提琴

DECLARE @start INT = 1000
DECLARE @end   INT = 1060

;WITH E1(N) AS(
    SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1 UNION ALL
    SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1 
)
,E2(N) AS(SELECT 1 FROM E1 a, E1 b)
,E4(N) AS(SELECT 1 FROM E2 a, E2 b)
,Tally(N) AS(
    SELECT TOP(@end - @start + 1) ROW_NUMBER() OVER(ORDER BY(SELECT NULL)) - 1 FROM E4
)
SELECT
    MIN(@start + t.N)
FROM Tally t
WHERE
    @start + t.N <= @end
    AND NOT EXISTS(
        SELECT 1 
        FROM OITM
        WHERE CAST(ItemCode AS INT) = @start + t.N
    )

这是另一个使用

sys.columns
生成计数表的查询:

;WITH Tally(N) AS(
    SELECT TOP(@end - @start + 1) ROW_NUMBER() OVER(ORDER BY(SELECT NULL)) - 1 
    FROM sys.columns a
    --CROSS JOIN sys.columns b
)
SELECT
    MIN(@start + t.N)
FROM Tally t
WHERE
    @start + t.N <= @end
    AND NOT EXISTS(
        SELECT 1 
        FROM OITM
        WHERE CAST(ItemCode AS INT) = @start + t.N
    )
© www.soinside.com 2019 - 2024. All rights reserved.