每个ID仅返回一次匹配对和非匹配对

时间:2019-04-08 18:40:19

标签: sql sql-server

任何帮助将不胜感激。

我这里有两个示例表。

表A:

ID |Name
123|REG
123|ERT
124|REG
124|ACR

表B

ID |Name
123|REG
123|WWW
124|REG
124|ADR

这是简单的连接输出,我将在评论中解释我的问题:

*是的-我要这一行

*否-我不要此行

AID|Aname|BID|Bname
123|REG  |123|REG  --Yes-- Matched-pair for id '123'
123|ERT  |123|REG  --No--'REG' already had one match. 'ERT' should pair with 'WWW' for id '123'
123|REG  |123|WWW  --No--The same reason as above
123|ERT  |123|WWW  --Yes--non-matched pair for id '123'
124|REG  |124|REG
124|ACR  |124|REG
124|REG  |124|ADR
124|ACR  |124|ADR

我想要的结果:

AID|Aname|BID|Bname
123|ERT  |123|WWW
123|REG  |123|REG
124|REG  |124|REG
124|ACR  |124|ADR

SQL Server 2017。

谢谢。


我的方法(由@The Impaler的帖子启发)

;with CTEall as(
select A.id as AID, A.NAME as Aname, b.id as BID,b.NAME as Bname  from A
inner join B on A.id = B.id),
match as (
select A.id as AID, A.NAME as Aname, b.id as BID,b.NAME as Bname  
from A inner join B on A.id = B.id and A.NAME = B.NAME)
select *
from CTEall 
where Aname not in (select Aname from match where AID = BID) 
and Bname not in (select Aname from match where BID = AID)
union all
select * from match
order by 1

2 个答案:

答案 0 :(得分:4)

通常,当您以不同的方式考虑所需的逻辑时,答案(或至少是答案)就会变得显而易见。

我这样想你的逻辑:

  

将表A与表B联接,以使A.ID = B.ID(始终)且以其他方式   A.Name = B.Name或A.Name在B中没有匹配项,并且B.Name没有   在A中有一场比赛。

这种逻辑在SQL中很容易表达

WHERE a.ID=b.ID 
AND (
  a.Name=b.Name OR (
    NOT EXISTS(SELECT * FROM TableB b2 WHERE b2.ID=a.ID AND b2.Name=a.Name)
    AND 
    NOT EXISTS(SELECT * FROM TableA a2 WHERE a2.ID=b.ID AND a2.Name=b.Name)
  )
)

答案 1 :(得分:1)

我会做的:

with
m as ( -- matched rows
  select a.id as aid, a.name as aname, b.id as bid, b.name as bname
  from table_a a
  join table_b b on a.id = b.id and a.name = b.name
),
l as ( -- unmatched "left rows"
  select a.id, a.name,
    row_number() over(partition by id order by name) as rn
  from table_a a
  left join table_b b on a.id = b.id and a.name = b.name
  where b.id is null
),
r as ( -- unmatched "right rows"
  select b.id, b.name,
    row_number() over(partition by id order by name) as rn
  from table_b b
  left join table_a a on a.id = b.id and a.name = b.name
  where a.id is null
)
select aid, aname, bid, bname from m
union all
select l.id, l.name, r.id, r.name
from l
join r on r.id = l.id and r.rn = l.rn

注意:此解决方案可能有点过大,因为当ID中有多个不匹配的行时,它们会匹配所有不匹配的行……这是不必要的。每个OP注释的每个ID总是有一个不匹配的行。