选择数据库表中不存在的所有ID

时间:2014-07-03 10:48:38

标签: sql sql-server

我有一个有2列的表。

Id,ItemValue,

id范围介于400000和409684之间。

id由sql server自动递增,但ID中存在一些空白。

例如

400001
400002
400003
400005 

所以在这种情况下缺少400004。

有没有办法让所有这些不存在的ID?

我可以选择一些select语句,我可以遍历所有ID并选择项目值,如果没有id,项目值是0吗?

6 个答案:

答案 0 :(得分:2)

试试这个

WITH IDRange AS(
Select 400000 AS ID
UNION ALL
SELECT ID+1
FROM IDRange
WHERE ID <= 409684
)
SELECT IR.ID FROM IDRange IR
LEFT OUTER JOIN <your_table> YT
ON IR.ID=YT.ID
WHERE YT.ID IS NULL
OPTION(MAXRECURSION 0)

答案 1 :(得分:1)

以下是执行此类事情的一般方法。

首先,您需要创建一个数字表。这样做的一个好方法是创建一个CTE来动态创建它们(如下所示:SQL, Auxiliary table of numbers

--===== Itzik's CROSS JOINED CTE method
   WITH E00(N) AS (SELECT 1 UNION ALL SELECT 1),
        E02(N) AS (SELECT 1 FROM E00 a, E00 b),
        E04(N) AS (SELECT 1 FROM E02 a, E02 b),
        E08(N) AS (SELECT 1 FROM E04 a, E04 b),
        E16(N) AS (SELECT 1 FROM E08 a, E08 b),
        E32(N) AS (SELECT 1 FROM E16 a, E16 b),
   cteTally(N) AS (SELECT ROW_NUMBER() OVER (ORDER BY N) FROM E32)
 SELECT N
   FROM cteTally
  WHERE N <= 1000000; -- Whatever the maximum value might be...

然后将其链接到您的表格并查找差距。由于你有一个非常具体的范围,整个答案看起来像这样:

   WITH E00(N) AS (SELECT 1 UNION ALL SELECT 1),
        E02(N) AS (SELECT 1 FROM E00 a, E00 b),
        E04(N) AS (SELECT 1 FROM E02 a, E02 b),
        E08(N) AS (SELECT 1 FROM E04 a, E04 b),
        E16(N) AS (SELECT 1 FROM E08 a, E08 b),
        E32(N) AS (SELECT 1 FROM E16 a, E16 b),
   cteTally(N) AS (SELECT ROW_NUMBER() OVER (ORDER BY N) FROM E32)
   SELECT numbers.N
   FROM cteTally AS numbers
   LEFT OUTER JOIN TableName AS yourtable
   ON numbers.N = yourtable.Id
   WHERE yourtable.Id IS NULL
   AND numbers.N BETWEEN 400000 AND 409684; -- Constrain to your required range

答案 2 :(得分:1)

我先create a numbers table

SELECT TOP (1000000) n = CONVERT(INT, ROW_NUMBER() OVER (ORDER BY s1.[object_id]))
INTO dbo.Numbers
FROM sys.all_objects AS s1 CROSS JOIN sys.all_objects AS s2
OPTION (MAXDOP 1);

CREATE UNIQUE CLUSTERED INDEX n ON dbo.Numbers(n)
-- WITH (DATA_COMPRESSION = PAGE)
;

现在您可以使用LEFT OUTER JOINNOT EXISTS

SELECT n AS ID 
FROM dbo.Numbers LEFT OUTER JOIN TableName t
    ON n = t.Id
WHERE n BETWEEN (SELECT MIN(id) FROM TableName) AND (SELECT MAX(id) FROM TableName)
AND t.Id IS NULL
  

我可以做一些选择语句,我可以通过所有   ids并选择项目值,如果没有id,项目值是否为0?

然后你只需要将NULL替换为0:

SELECT ISNULL(t.Id, 0) AS Id
FROM dbo.Numbers LEFT OUTER JOIN TableName t
    ON n = t.Id
WHERE n BETWEEN (SELECT MIN(id) FROM TableName) AND (SELECT MAX(id) FROM TableName)

答案 3 :(得分:1)

DECLARE @low int = 400001, @high int = 400005
DECLARE @t table(id int)

INSERT @t values(400001),(400002),(400003),(400005)

;WITH CTE as
(
SELECT @low id
UNION ALL
SELECT id + 1
FROM CTE WHERE id < @high
)
SELECT id FROM CTE
EXCEPT
SELECT id FROM @t
OPTION (MAXRECURSION 0)

答案 4 :(得分:0)

我使用了IF EXISTSELSE

DECLARE @counter INT

DECLARE @QualifyingItems TABLE (
        IdINT, 
        Value MONEY)

SELECT @counter = 400000
WHILE @counter < 409688
BEGIN  

  IF EXISTS(SELECT b.Id, b.Value FROM dbo.Items WHERE Id= @counter) 
    BEGIN
        INSERT INTO @QualifyingItems SELECT b.Id, b.Value FROM dbo.Items b WHERE Id= @counter
    END
ELSE
    BEGIN
        INSERT INTO @QualifyingItems SELECT @counter, 0 
    END
  SELECT @counter = @counter + 1  

END

SELECT * FROM @QualifyingItems 

答案 5 :(得分:0)

  

有没有办法让所有这些不存在的ID?

这将返回不存在的ID的范围

WITH cte AS
   (SELECT [id], ROW_NUMBER() OVER (ORDER BY id) rw
    FROM MyTable
    WHERE id > 400000 AND id < 409684)
   ,cte2 as
   (
    SELECT id, rw, id-rw as dif FROM cte
   )
   ,cte3 as
   (
    SELECT id, rw, dif, RANK() OVER (ORDER BY dif) difRank from cte2
   )

SELECT c1.id + 1 AS StartRange, c2.ID - 1 AS EndRange
FROM cte3 c1 JOIN cte3 c2 ON c1.difRank != c2.difRank AND c1.rw = c2.rw - 1