2015-04-23 46 views
4

我有一個類似數據的表。選擇一個範圍內的最小數量

ItemCode 
1000 
1002 
1003 
1020 
1060 

我想寫一個SQL語句來獲得的最低數量(ItemCode)未在該表中,它應該是能夠得到一個最低數,一旦前面的最小訂單ID已經被插入在表中,但也跳過已經在數據庫中的數字。每次查詢運行時我只想得到1個結果。

因此,它應該得到1001作爲基於上表的第一個結果。一旦ItemCode = 1001已被插入到表格中,應該得到的下一個結果應該是1004,因爲10001003已經存在於表格中。

基於我在網上看到的一切,我認爲,我必須使用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 

我覺得有一個更簡單的方法來實現這一點。有沒有辦法讓我說......

選擇未在表中存在1000和1060之間的最小數量的X

編輯:創建一個新的表不是一個選項,我案例

最後編輯:謝謝你們!我知道了。這是我最後的查詢,返回我想要的。我知道我沒有理由讓它變得太複雜了!

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

您不需要創建表,您可以根據wewesthemenace提供的解決方案使用'CTE'或'sys.columns' – ughai

回答

1

這應該做的事情。在這裏,您將爲行生成序列號,然後將每行與下一行進行比較(通過連接條件完成),並僅在差異不爲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 
1

您可以使用Tally表完成此操作。查看Jeff Moden的article以供參考。

基本上,您要生成從@start@end的數字。這就是Tally表的來源,它將用於數字生成。當你有你的號碼時,你只需要檢查表中不存在的最小值。

SQL Fiddle

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 
    ) 
1

你可以使用row_number()產生連續值的每一行,再看看對於row_number()與表中存儲的值不匹配的第一行。我的SQL Server安裝此時不工作,SQL小提琴似乎太過了,所以我寫了這個,而不能對其進行測試,但這樣的事情應該工作:

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陳述出於某種原因,所以我硬編碼的邊界,而是希望它仍然能夠通過這個想法。

相關問題