我需要从下面的表#a
中找到缺少的ID:
id |SEQ|Text
1 |1 |AA
1 |3 |CC
1 |4 |DD
1 |5 |EE
1 |6 |FF
1 |7 |GG
1 |8 |HH
1 |10 |JJ
2 |1 |KK
2 |2 |LL
2 |3 |MM
2 |4 |NN
2 |6 |PP
2 |7 |QQ
3 |1 |TT
3 |4 |ZZ
3 |5 |XX
表#a
的最大值和最小值SEQ存储在另一个表#b
中:
id| mn| mx
1 | 1 | 12
2 | 1 | 9
3 | 1 | 5
我的查询是提供正确的输出,但执行费用很高。还有另一种解决方法吗?
with cte
as
(
select id, mn, mx
from #b
union all
select id, mn, mx -1
from cte
where mx-1 > 0
)
select
cte.id, cte.mx
from
cte
left join #a on cte.id = #a.id and cte.mx = #a.seq
where
#a.seq is null
order by cte.id, cte.mx
此查询主要有两个问题:
答案 0 :(得分:2)
您使用递归CTE到generate a set of numbers。这是非常低效的方法(请参阅生成50K数字的图表here)。我建议在数据库中有一个持久的数字表。我个人有一个表Numbers
,其中包含100K行和一列Number
,这是一个主键,其整数从1到100,000。
一旦有了这样的表格,您的查询就会简化为:
SELECT
#b.id, #b.mx
FROM
#b
INNER JOIN Numbers ON
#b.mx >= Numbers.Number AND
#b.mn <= Numbers.Number -- use this clause if mn can be more than 1
LEFT JOIN #a ON
#a.id = #b.id AND
#a.seq = Numbers.Number
WHERE
#a.seq IS NULL
ORDER BY #b.id, #b.mx
此外,毋庸置疑,您必须确保#b
上的id
上有索引,#a
上的(id, seq)
上的索引。
答案 1 :(得分:1)
我想到的两件事是:
使用数字/计数表。通过创建普通表或使用CTE创建虚拟。用它来查找不存在的数字。
如果没有很多丢失的数字,你可以使用row_number()的技巧找到没有任何空白的数字范围,如下所示:
select id, min(seq), max(seq)
from (
select
id,
seq,
seq - row_number () over (partition by id order by SEQ asc) GRP
from
table1
) X group by id, GRP
order by 1
在您找到存在的数字范围后,这当然需要更多处理。
答案 2 :(得分:0)
CTE只是语法,最有可能多次评估 将CTE输出物化为#temp并加入#temp