我有一个有2列的表。
Id,ItemValue,
id范围介于400000和409684之间。
id由sql server自动递增,但ID中存在一些空白。
例如
400001
400002
400003
400005
所以在这种情况下缺少400004。
有没有办法让所有这些不存在的ID?
我可以选择一些select语句,我可以遍历所有ID并选择项目值,如果没有id,项目值是0吗?
答案 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)
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 JOIN
或NOT 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 EXISTS
和ELSE
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