2012-02-24 51 views
1

我有以下文件名更改日志表。获取最旧的名字(递归)?

ChangeNameLog(日期OLDNAME,新名称)
主键:日期OLDNAME

表的数据看起来像

 
Date OldName NewName 
1/1 aaa  bbb 
1/2 bbb  ccc 
1/3 ccc  bbb 
1/4 bbb  ddd 
2/1 xx  yy 
2/2 yy  zz 

(文件名aaa改为bbb,然后CCCBBBDDD
文件名XX改为YY,然后ZZ

我想要得到的最古老的名为所有新的名字。结果看起来像

 
Date NewName OldestName 
1/2 bbb  aaa 
1/3 ccc  aaa 
1/4 ddd  aaa 
2/1 yy  xx 
2/2 zz  xx 

无论如何编写一个Transact-SQL(版本2008罚款)没有使用光标循环日志表?

以下SQL可用于准备数据。

declare @log table (
    Date Date, OldName varchar(20), NewName varchar(20) not null 
    primary key (Date, OldName) 
); 
-- The real table also have the following CK 
-- create unique index IX_CK on @log (Date, NewName) 

insert into @log values 
('2012-01-01', 'aaa', 'bbb') 
,('2012-01-02', 'bbb', 'ccc') 
,('2012-01-03', 'ccc', 'bbb') 
,('2012-01-04', 'bbb', 'ddd') 
,('2012-01-05', 'ddd', 'eee') 

,('2012-01-03', 'xx', 'yy') 
,('2012-02-02', 'yy', 'zz') 
,('2012-02-03', 'zz', 'xx') 
; 
+1

我不确定,但我相当肯定你需要更具体和更深入的解释你所面临的问题,以便接收任何有用的答案。 – Zyerah 2012-02-24 23:47:27

+0

看看:http://stackoverflow.com/questions/1757370/recursive-same-table-query-in-sql-server-2008其中处理同样的事情(递归查询) – Eddy 2012-02-24 23:57:18

+0

CTE是唯一的方法。 – SQLMason 2012-02-25 00:28:04

回答

0

自己的解决方案:

declare @log table (
    Date Date, OldName varchar(20), NewName varchar(20) 
    primary key (Date, OldName) 
); 

insert into @log values 
('2012-01-01', 'aaa', 'bbb') 
,('2012-01-02', 'bbb', 'ccc') 
,('2012-01-03', 'ccc', 'bbb') 
,('2012-01-04', 'bbb', 'ddd') 
,('2012-01-05', 'ddd', 'eee') 

,('2012-01-03', 'xx', 'yy') 
,('2012-02-02', 'yy', 'zz') 
,('2012-02-03', 'zz', 'xx') 
; 

;with m as (
    select Date, OldName, NewName, 1 as L 
    from @log 
    union all 
    select l.Date, m.OldName, l.NewName, L + 1 
    from @log l join m on l.Date > m.Date and l.OldName = m.NewName 
) 
select * 
from m 
where L = (select MAX(l) from m m1 where NewName = m.NewName and Date = m.Date) 
order by 1 

输出:
下面的结果表明,这两种原始的名字是AAAXX

 
Date  Orig Name L 
2012-01-01 aaa bbb 1 
2012-01-02 aaa ccc 2 
2012-01-03 aaa bbb 3 
2012-01-03 xx yy 1 
2012-01-04 aaa ddd 4 
2012-01-05 aaa eee 5 
2012-02-02 xx zz 2 
2012-02-03 xx xx 3 
+0

我不明白这是一个“解决方案” - 它不会给出任何输出,例如您在问题中列出的预期结果。 – 2012-02-25 06:52:23

3

设置:

declare @logtable table (Date date, OldName nvarchar(200), NewName varchar(200)) 

insert into @logtable values (convert (date, '1/1/12', 1), 'aaa', 'bbb') 
insert into @logtable values (convert (date, '1/2/12', 1), 'bbb', 'ccc') 
insert into @logtable values (convert (date, '1/3/12', 1), 'ccc', 'bbb') 
insert into @logtable values (convert (date, '1/4/12', 1), 'bbb', 'ddd') 
insert into @logtable values (convert (date, '2/1/12', 1), 'xx', 'yy') 
insert into @logtable values (convert (date, '2/2/12', 1), 'yy', 'zz') 

现在到递归CTE。第一部分(回溯)在日志表上匹配过去的名字并保留链顶端的信息(EndName)。第二部分,首发者通过改变分配EndName的行号,最后只显示最旧的记录。这部分可能用更多的方式表达,使用不存在于changedate,或在每个日志条目中保留原始名称,但是如果此代码证明过慢,我会调查另一种方法。

; with backtrack as (
    select NewName EndName, NewName, OldName, Date 
     from @logtable 
    union all 
    select EndName, [@logtable].NewName, [@logtable].OldName, [@logtable].Date 
    from @logtable inner join backtrack 
     on [@logtable].NewName = backtrack.OldName 
     and [@logtable].Date < backtrack.Date 
), 
starters as (
    select EndName NewName, OldName, Date, ROW_NUMBER() over (partition by EndName order by Date) RowNumber 
    from backtrack 
) 
select NewName, OldName 
from starters 
where RowNumber = 1 

我希望这会帮助你。

+0

不错的工作。我也想出了一个少线条的解决方案。 – ca9163d9 2012-02-25 06:57:40

0

或者,对于不同的头痛,通过转发plods:

declare @Helga as table (Date datetime, OldName varchar(10), NewName varchar(10)) 
insert into @Helga (Date, OldName, NewName) values 
    ('1/1/12', 'aaa', 'bbb'), ('1/2/12', 'bbb', 'ccc'), ('1/3/12', 'ccc', 'bbb'), 
    ('1/4/12', 'bbb', 'ddd'), ('2/1/12', 'xx', 'yy'), ('2/2/12', 'yy', 'zz') 
select * from @Helga 

; with Edmund as 
(-- Get the oldest names. 
    select L.Date, L.OldName, L.NewName, L.OldName as Methuselah, cast(0 as bigint) as Ethyl 
    from @Helga as L left outer join 
     @Helga as R on R.NewName = L.OldName 
    where R.NewName is NULL 
    union all 
    -- Add newer names one generation at a time. 
    select H.Date, H.OldName, H.NewName, H.Methuselah, H.Sandy 
    from (select iH.Date, iH.OldName, iH.NewName, Ed.Methuselah, Row_Number() over (order by iH.Date) as Sandy 
     from Edmund as Ed cross join 
     @Helga as iH where iH.OldName = Ed.NewName and iH.Date > Ed.Date) as H 
    where H.Sandy = 1 
) 
select Date, OldName, NewName, Methuselah 
    from Edmund 
    order by Methuselah, Date 

当然,如果您分配了一致的标识每个您在名称更改文件仍然存在,这将是更容易,更可靠。当您有纽约州>新泽西州>马萨诸塞州交叉路径与MN>马> CA> AL所有投注都关闭。如果第一个序列进行FileId 1,第二个序列是2,则仍然可以理清细节。