从连接的键中选择最大键

时间:2014-07-14 19:55:48

标签: sql sql-server join self-join

我有一个表,其中包含已更改为其他键的键。这些都是这样的:

origkey newkey
1        2
2        3
4        5
6        7
7        8
8        9
9        10

我想要完成的是一个获取orig的查询,并找到每个新的最大新密钥。在上面的示例中,结果如下所示:

origkey maxkey
1        3
4        5
6        10

如果我知道密钥可以更改的最大次数,我只需添加一定量的自联接并从那里获取。不幸的是,我不知道它过去可能改变了多少次。有没有办法保持自我加入,直到找到一个空?以下查询会将更改后的密钥返回到新列中,但我认为我在这里走错路,因为这样会得到1 - > 3改变,但不是6 - > 10改变。

select a.origkey
,a.newkey
,b.newkey newkey1
,c.newkey newkey2 
from changedkeys a
Left Outer Join changedkeys b on a.newkey=b.origkey
Left Outer Join changedkeys c on b.newkey=c.origkey

1 个答案:

答案 0 :(得分:1)

有一种方法。它被称为递归CTE:

with cte as (
      select origkey, newkey, 1 as lev
      from table1
      union all
      select cte.origkey, t1.newkey, lev + 1
      from cte join
           table1 t1
           on cte.newkey = t1.origkey
    )
select origkey, newkey as newestkey
from (select cte.*, row_number() over (partition by origkey order by lev desc) as seqnum
      from cte
     ) t
where seqnum = 1;

请注意,这假定键定义中没有循环,如问题中的示例所示。如果这是可能的,可以修改递归CTE来处理这个问题。

编辑:

如果数据中有潜在的周期,请尝试以下方法:

with cte as (
      select origkey, newkey, 1 as lev, ',' + cast(newkey as varchar(8000)) + ',' as keys
      from table1
      union all
      select cte.origkey, t1.newkey, cte.lev + 1, keys + cast(t1.newkey as varchar(8000)) + ','
      from cte join
           table1 t1
           on cte.newkey = t1.origkey
      where ',' + t1.keys + ',' not like '%,' + cast(t1.newkey as varchar(8000)) + '%,'
    )
select origkey, newkey as newestkey
from (select cte.*, row_number() over (partition by origkey order by lev desc) as seqnum
      from cte
     ) t
where seqnum = 1;