我有数据,其中增量序列在某处被破坏,可能是多次。 例如。 (2,3,4,5,6,8,10)。
我想得到:
使用SQL(最好是通用的,适用于oracle和mysql以及其他sql平台)。
使用序列或auto_increment是特定于平台的。
我尝试过像
这样的自连接构造select curr.id+1 as first_fail from junk as prev
join junk as curr
on (prev.id+1 = curr.id)
order by curr.id desc limit 1;
(http://sqlfiddle.com/#!9/bae781/4/0) 但它看起来很丑陋,并且无法获得"破坏"这样放置。
答案 0 :(得分:3)
检查一下:
select prev_id+1 as first_fail,count(*)-1 as total_broken from
(
select curr.id as curr_id,prev.id as prev_id
from junk as prev
left join junk as curr on prev.id+1 = curr.id
) sub where sub.curr_id is null ;
SQL小提琴示例:http://sqlfiddle.com/#!9/bae781/62
查询Gap是否大于1
select p2_id-1 as first_fail,sum(broken) as total_broken from
(select p1.row_num as p1_row,p2.row_num as p2_row,p1.id as p1_id,p2.id as p2_id,(p2.id-p1.id-1) as broken from
(
select @row_num:=@row_num+1 as row_num,junk.id
from junk,(select @row_num:=0) s1
) p1
left join
(
select @row_num2:=@row_num2+1 as row_num,junk.id
from junk,(select @row_num2:=0) s2
) p2 on p1.row_num+1=p2.row_num ) as sub
where broken is not null and broken > 0;
SQL小提琴演示:http://sqlfiddle.com/#!9/974ec/1
答案 1 :(得分:2)
您可以生成计数表并使用LEFT JOIN
:
SELECT MIN(SeqValue)-1 AS `first`, COUNT(*) AS `total`
FROM (
SELECT
(TWO_1.SeqValue + TWO_2.SeqValue + TWO_4.SeqValue + TWO_8.SeqValue + TWO_16.SeqValue) SeqValue
FROM
(SELECT 0 SeqValue UNION ALL SELECT 1 SeqValue) TWO_1
CROSS JOIN (SELECT 0 SeqValue UNION ALL SELECT 2 SeqValue) TWO_2
CROSS JOIN (SELECT 0 SeqValue UNION ALL SELECT 4 SeqValue) TWO_4
CROSS JOIN (SELECT 0 SeqValue UNION ALL SELECT 8 SeqValue) TWO_8
CROSS JOIN (SELECT 0 SeqValue UNION ALL SELECT 16 SeqValue) TWO_16
) AS tally
LEFT JOIN junk
ON junk.id = tally.SeqValue
WHERE tally.SeqValue >= (SELECT MIN(id) FROM junk)
AND tally.SeqValue <= (SELECT MAX(id) FROM junk)
AND junk.id IS NULL;
的 SqlFiddleDemo
强>
有很多方法可以生成计数表(CTE/recursive CTE/subquery/table function/variables/windowed function
)。
您可以轻松地交换计数子查询(我的示例仅提供有限的范围)。
修改强>
为MySQL
快速扩展它的一种方法是use multiple CROSS JOIN
:
SELECT MIN(SeqValue)-1 AS `first`, COUNT(*) AS `total`
FROM (select (@rn := @rn + 1) - 1 as SeqValue
from (select 0 as n union all select 1 union all select 2 union all select 3 union all select 4 union all select 5 union all select 6 union all select 7 union all select 8 union all select 9) d1 cross join
(select 0 as n union all select 1 union all select 2 union all select 3 union all select 4 union all select 5 union all select 6 union all select 7 union all select 8 union all select 9) d2 cross join
(select 0 as n union all select 1 union all select 2 union all select 3 union all select 4 union all select 5 union all select 6 union all select 7 union all select 8 union all select 9) d3 cross join
(select 0 as n union all select 1 union all select 2 union all select 3 union all select 4 union all select 5 union all select 6 union all select 7 union all select 8 union all select 9) d4 cross join
(select 0 as n union all select 1 union all select 2 union all select 3 union all select 4 union all select 5 union all select 6 union all select 7 union all select 8 union all select 9) d5 cross join
(select 0 as n union all select 1 union all select 2 union all select 3 union all select 4 union all select 5 union all select 6 union all select 7 union all select 8 union all select 9) d6 cross join
(select @rn := 0) params
) AS tally
LEFT JOIN junk
ON junk.id = tally.SeqValue
WHERE tally.SeqValue >= (SELECT MIN(id) FROM junk)
AND tally.SeqValue <= (SELECT MAX(id) FROM junk)
AND junk.id IS NULL;
答案 2 :(得分:1)
这是在寻找之前跳过了多少个id,以及最后一次是什么:
SET @i:=0, @last:=0;
SELECT id, skipped_before, last_correct FROM (
SELECT id,
@i:=@i+1 row_num,
id-@i-1 skipped_before,
if(id-@i=1,@last:=id,@i:=@i+id-@last-1),
@last last_correct
FROM junk
) a
WHERE skipped_before;
断链计数是skipped_berore>0
计数的行
First fail
显然是最小的last_correct+1
错过的ID计数为sum(skipped_before)
,
但是这可以通过
SELECT MAX(id)-MIN(id)-COUNT(id)+1 FROM junk;
答案 3 :(得分:1)
按ids排序的所有开头“中断”:
select j1.id + 1 as id
from junk j1
left join junk j2 on j2.id = j1.id + 1
where j2.id is null
and j1.id <> (select max(id) from junk)
order by j1.id;
选择第一行以获得第一个“休息”。计算行数以获得“休息”的数量。
如果您需要所有缺失ID的数量:
-- get number of missing ids
select
-- num rows you should have
(select max(id) from junk) - (select min(id) from junk) + 1
-- num rows you really have
- count(*) as num_missings
from junk;
或更短:
select max(id) - min(id) + 1 - count(*) as num_missings from junk;