2012-02-24 47 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,則仍然可以理清細節。