使用每行一次进行完全外连接

问题描述 投票:0回答:3

我想知道是否有人找到解决这个问题的巧妙方法。我试图从几个表中选择数据,让记录逐行匹配。我基本上追求的是完整的外部连接,但有一个关键的区别。如果我在一个表中连接的列中有四行具有特定值,而另一个表中有三行具有该值,我只希望连接前三个结果,第四个结果就像有一直不匹配。

这样做的原因是创建一个对账报告,以确保在比较结果时不会多次计算交易。我可以通过使用一些分组和一些聚合函数来解决这个问题,但这隐藏了我想保留的一些细节。

下面是一个示例,展示了我想要的东西,注释中的无效/伪代码说明了我如何认为这是有效的:

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

sql sql-server join outer-join
3个回答
5
投票

如果我理解正确,这可能就是你想要的:

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

1
投票

用完行的最佳方法是添加伪行号(使用 ROW_NUMBER)并将其包含在联接中。


0
投票

给出的答案就是所需要的。如果提供上下文有帮助,只需提及反答案即可。对于实现该行为的语法上更简洁的方法,但目前支持,将是:

full outer apply (select top(1) * ...)
© www.soinside.com 2019 - 2024. All rights reserved.