2012-06-06 47 views
4

我想知道是否有人遇到這個問題的簡潔解決方案。我試圖從幾個表中選擇數據,讓記錄逐行匹配。我基本上是在完全外連接之後,但有一個關鍵的區別。如果我在一個表格中加入了四行中的特定值,並且在另一個表格中加入了三行,並且這個值在另一個表格中,我只想要加入前三個結果,第四個行爲就好像有一直沒有匹配。完全外部聯接使用每行一次

其原因是創建一個對帳報告,確保在比較結果時交易不會被多次計數。我可以通過使用一些分組和一些聚合函數來解決這個問題,但是這隱藏了一些我想保留的細節。

下面是一個例子來說明之類的事情後,我與註釋中的無效/僞代碼說明我如何思考這個作爲工作:

declare @t1 table (id bigint identity(1,1) primary key clustered, foreignKeyId bigint, otherData nvarchar(10)) 
declare @t2 table (id bigint identity(1,1) primary key clustered, foreignKeyId bigint, moreData nvarchar(10)) 

insert @t1 select 1, '1.1.1' 
union all select 1, '1.1.2' 
union all select 1, '1.1.3' 
union all select 3, '1.3.1' 
union all select 3, '1.3.2' 
union all select 3, '1.3.3' 
union all select 4, '1.4.3' 

insert @t2 select 1, '2.1.1' 
union all select 1, '2.1.2' 
union all select 1, '2.1.3' 
union all select 2, '2.2.1' 
union all select 3, '2.3.1' 
union all select 3, '2.3.2' 
union all select 5, '2.5.1' 
union all select 5, '2.5.2' 

--demo of the functionality i'm hoping to acheive 
-- 
/* 
select t1.id   id1 
, t2.id    id2 
, t1.foreignKeyId fk1 
, t2.foreignKeyId fk2 
, t1.otherData  otherData 
, t2.moreData  moreData 
from @t1 t1 
full funky join @t2 t2 
on t1.foreignKeyId = t2.foreignKeyId 
order by t1.id, t2.id --we'd need an order by to ensure the match could be applied in a predictable manner 
*/ 
-- 
declare @funkyjoin table (id1 bigint, id2 bigint, fk1 bigint, fk2 bigint, otherData nvarchar(10), moreData nvarchar(10)) 
declare @id1 bigint, @id2 bigint 
insert @funkyjoin (id1, fk1, otherData) 
select id, foreignKeyId, otherData from @t1 

while exists(select 1 from @t2) 
begin 
    select top 1 @id2 = id from @t2 order by id 

    set @id1 = null 

    select top 1 @id1 = id1 
    from @funkyjoin 
    where fk2 is null 
    and fk1 in (select foreignKeyId from @t2 where id = @id2) 

    if @id1 is null 
    begin 
     insert @funkyjoin (id2, fk2, moreData) 
     select id, foreignKeyId, moreData 
     from @t2 
     where id = @id2 
    end 
    else 
    begin 
     update @funkyjoin 
     set id2 = @id2 
     , fk2 = fk1 --since we're joining on this we can just match it 
     , moreData = (select moreData from @t2 where id = @id2) 
     where id1 = @id1 
    end 

    delete from @t2 where id = @id2 --since this is only an example let's not worry about keeping our source data 
end 

select * 
from @funkyjoin 
order by coalesce(id1, id2) 

我寫一個類似的解決方案,用於以前的電子表格中出現此情形時:http://officemacros.codeplex.com/#WorksheetMergeMacro

+0

FYI:一個同事剛剛指着我作爲一個潛在的解決這個問題離奇更新的方向:HTTP:// www.simple-talk.com/sql/learn-sql-server/robyn-pages-sql-server-cursor-workbench/。我現在正在閱讀這篇文章,但第一眼看起來很有希望。 。 。 – JohnLBevan

+3

古怪的更新不受支持,未記錄,可能在將來無法使用。我建議避免它。 –

回答

3

如果我理解正確的話,這可能是你追求的:

select * 
from (
    select *, 
    row_number() over (partition by foreignKeyId order by id) as n 
    from @t1 
) t1 
full outer join (
    select *, 
    row_number() over (partition by foreignKeyId order by id) as n 
    from @t2 
) t2 on t1.foreignKeyId = t2.foreignKeyId and t1.n = t2.n 
+0

啊,當然 - 我有一種感覺,我的老朋友分區將涉及,但沒有完全達到那裏。謝謝乍得。 – JohnLBevan

1

用盡行的最佳方式是添加僞行號(使用ROW_NUMBER)並將其包含在聯接中。

相關問題