我有一张像这样的桌子:
id
number
year
我想找到“漏洞”或差距,不考虑 id 而只考虑几年/数字。
当同一年有两个不连续的数字时存在差距,结果是年份和这两个不连续数字之间的所有数字(不包括极端数字)。另请注意,下端始终为 1,因此如果缺少 1,则为间隙。
例如,拥有:
id n year
1 1 2012
2 2 2012
3 5 2012
4 2 2010
我想要的结果是:
3/2012
4/2012
1/2010
在序列中查找缺失条目的技巧是生成序列中所有可用组合的笛卡尔积,然后用于NOT EXISTS消除那些存在的组合。这很难以非 DBMS 特定的方式完成,因为它们都有不同的方式来优化动态创建序列。对于 Oracle,我使用:
SELECT RowNum AS r
FROM Dual
CONNECT BY Level <= MaxRequiredValue;
因此,要生成所有可用 year/n 对的列表,我将使用:
SELECT d.Year, n.r
FROM ( SELECT year, MAX(n) AS MaxN
FROM T
GROUP BY Year
) d
INNER JOIN
( SELECT RowNum AS r
FROM Dual
CONNECT BY Level <= (SELECT MAX(n) FROM T)
) n
ON r < MaxN;
我得到每年的最大值 n 并将其加入从 1 到最高 n 的整数列表中,其中该整数列出的最大值小于该年份的最大值。
最后用于NOT EXISTS消除已经存在的值:
SELECT d.Year, n.r
FROM ( SELECT year, MAX(n) AS MaxN
FROM T
GROUP BY Year
) d
INNER JOIN
( SELECT RowNum AS r
FROM Dual
CONNECT BY Level < (SELECT MAX(n) FROM T)
) n
ON r = MaxN
WHERE NOT EXISTS
( SELECT 1
FROM T
WHERE d.Year = t.Year
AND n.r = t.n
);
SQL Fiddle上的工作示例
编辑
由于我找不到非 DMBS 特定的解决方案,我想我最好做点正经的事,并为其他 DBMS 创建一些示例。
另一种选择是使用这样的临时表:
create table #tempTable ([year] int, n int)
insert
into #tempTable
select t.year, 1
from tableName t
group by t.year
while exists(
select *
from tableName t1
where t1.n > (select MAX(t2.n) from #tempTable t2 where t2.year = t1.year)
)
begin
insert
into #tempTable
select t1.year,
(select MAX(t2.n)+1 from #tempTable t2 where t2.year = t1.year)
from tableName t1
where t1.n > (select MAX(t2.n) from #tempTable t2 where t2.year = t1.year)
end
delete t2
from #tempTable t2
inner join tableName t1
on t1.year = t2.year
and t1.n = t2.n
select [year], n
from #tempTable
drop table #tempTable