任务如下:我有一个表“数字”,只有一列“数字”。此表中的数字在范围a ... b中,每个特定数字仅出现在表格中一次。我需要找到范围a..b中缺少的数字。还有一件事是范围可能非常大,性能应该仍然很好。我想出了找到所有数字对的想法,在这些数字对之间缺少数字,所以我们不必比较这个范围内的所有数字并以这种方式提高性能。下一个查询返回所有这些数字对:
select N1.number as num1, MIN(N2.number)as num2 from numbers N1 join numbers N2 on N2.number > N1.number
and N2.number - N1.number > 1
and not exists (select * from numbers where number > N1.number and number < n2.number)
group by n2.number, n1.number
集1 2 3 4 6 8 10的结果是:
4 6
6 8
8 10
现在我想列出所有数字,但是我坚持了,我没有在其他select语句或其他任何内容中传递这些数字对并使其成为一个查询。有任何想法吗?它有可能吗?
答案 0 :(得分:0)
您必须有一个所有号码列表,以便与(here's an example for that)进行比较。现在,如果你在名为“all_numbers”的表中有这些数字,你可以这样做:
select a.number from all_numbers a
where a.number not in (select N1.number from numbers N1)
或者,您可以通过添加以下过滤条件来限制“缺失”数字的范围:
and a.number between (select min(number) from numbers)
and (select max(number) from numbers)
这取决于你需要多么复杂,但你肯定需要从所有相关数字的列表开始。
答案 1 :(得分:0)
我认为这是您需要的查询:
select nstart,
nend
from (select m.startNumber + 1 as nstart,
(select min(startNumber) - 1
from numbers x
where x.startNumber > m.startNumber) as nend
from numbers m
left join
(select startNumber-1 startNumber
from numbers r) r
on (m.startNumber = r.startNumber)
where r.startNumber is null
) x
where nend is not null
order by nstart
在这里查看小提琴:http://sqlfiddle.com/#!2/720b1/4
需要注意的重要事项是@GordonLinoff发表的评论:
Without some constraints on the problem, it is hard to come up with an
efficient solution. After all, the table could contain two values,
such as 1 and 1,000,000,000
答案 2 :(得分:0)
谢谢大家,伙计们,我将你提出的所有解决方案结合起来,最后提出了这个解决方案:
WITH
L0 AS(SELECT 1 AS c UNION ALL SELECT 1),
L1 AS(SELECT 1 AS c FROM L0 AS A CROSS JOIN L0 AS B),
L2 AS(SELECT 1 AS c FROM L1 AS A CROSS JOIN L1 AS B),
L3 AS(SELECT 1 AS c FROM L2 AS A CROSS JOIN L2 AS B),
L4 AS(SELECT 1 AS c FROM L3 AS A CROSS JOIN L3 AS B),
L5 AS(SELECT 1 AS c FROM L4 AS A CROSS JOIN L3 AS B),
Nums AS(SELECT ROW_NUMBER() OVER(ORDER BY (SELECT NULL)) AS n FROM L5)
select n from Nums as Nmbrs
inner join
(select N1.number as num1, MIN(N2.number)as num2 from numbers N1 join numbers N2 on N2.number > N1.number
and N2.number - N1.number > 1
and not exists (select * from numbers where number > N1.number and number < n2.number)
group by n2.number, n1.number) T on Nmbrs.n>num1 and Nmbrs.n < num2
order by Nmbrs.n
工作速度非常快,我使用Fibonacci数字进行测试,1 ... 1 000 000在7秒内处理,1 ... 1 000 000 000在69秒内处理,以及最重要的是什么,它&& #39;单个查询。
答案 3 :(得分:0)
我认为使用CTE的递归查询可以对您有所帮助:
WITH CTE (i, sw)
AS (SELECT 1 AS i, 'SW_00000' -- anchor member
UNION ALL
SELECT i + 1, 'SW_' + RIGHT('00000' + cast(i+1 as varchar),5) -- recursive member
FROM cte
WHERE i < 5000 -- terminator
)
SELECT i,sw -- Display CTE result
FROM cte
where sw not in ( -- exclude existing values
select... <query existing stuff here>
)
OPTION (MAXRECURSION 5000); -- default max for recursion = 200