我有一个包含数据的表格。
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');
答案 0 :(得分:1)
您可以使用Tally Table执行此操作。请查看Jeff Moden的article作为参考。
基本上,您希望生成从@start
到@end
的数字。这就是Tally Table的用武之地。它将用于数字生成。如果有数字,则只需检查表中不存在的最小值。
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
生成Tally表的查询:
;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
)
答案 1 :(得分:1)
您可以使用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小提琴。我不知道为什么该网站之前没有为我工作。由于某些原因,它似乎不喜欢我的declare
语句,所以我改为编码边界,但希望它仍然可以得到这个想法。
答案 2 :(得分:1)
这应该做的事情。在这里,您将为行生成sequantial数字,然后将每行与下一行(通过连接条件完成)进行比较,并仅在差异不为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