我有一个包含类似数据的表格。
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');
这应该可以解决问题。在这里,您为行生成序号,然后将每一行与下一行进行比较(通过连接条件完成),并仅过滤差异不为 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
您可以使用
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
语句,因此我对边界进行了硬编码,但希望它仍然能传达这个想法。
您可以使用计数表来完成此操作。查看 Jeff Moden 的这篇文章以供参考。
基本上,您想要生成从
@start
到 @end
的数字。这就是计数表的用武之地。它将用于数字生成。当您获得数字后,您只需检查表中不存在的最小值即可。
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
)