sql在几年/年中找到差距

时间:2012-06-26 09:32:33

标签: sql select self-join

我有一张表:

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

2 个答案:

答案 0 :(得分:3)

在序列中查找缺失条目的技巧是生成序列中所有可用组合的笛卡尔积,然后使用NOT EXISTS来消除存在的那些。这在非DBMS特定方式中很难做到,因为它们都有不同的方式可以在运行中选择性地创建序列。对于Oracle,我使用:

SELECT  RowNum AS r
FROM    Dual
CONNECT BY Level <= MaxRequiredValue;

因此,要生成所有可用年/ 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创建一些示例。

SQL Server Example

Postgresql Example

My SQL Example

答案 1 :(得分:0)

另一种选择是使用像这样的临时表:

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