比较两个表中的主要/别名组
Posted
技术标签:
【中文标题】比较两个表中的主要/别名组【英文标题】:compare primary/alias groups across two tables 【发布时间】:2018-11-28 19:57:22 【问题描述】:生日,
我们有两个包含完全相同结构的表。有两列“PrimaryAddress”和“AliasAddress”。这些用于电子邮件地址和别名。我们希望找到任何需要添加到任一方 的记录以保持记录同步。问题是一个表中的主名称可能在另一个表中列为别名。好消息是地址不会在“AliasAddress”列中出现两次。
TABLE A
PrimaryAddress~~~~~AliasAdress
chris@work~~~~~~~~~chris@home
chris@work~~~~~~~~~c@work
chris@work~~~~~~~~~theboss@work
chris@work~~~~~~~~~thatguy@aol
bob@test~~~~~~~~~~~test1@test
bob@test~~~~~~~~~~~charles@work
bob@test~~~~~~~~~~~chuck@aol
sally@mars~~~~~~~~~sally@nasa
sally@mars~~~~~~~~~sally@gmail
TABLE B
PrimaryAddress~~~~~AliasAdress
chris@home~~~~~~~~~chris@work
chris@home~~~~~~~~~c@work
chris@home~~~~~~~~~theboss@work
chris@home~~~~~~~~~thatguy@aol
bob@test~~~~~~~~~~~test1@test
bob@test~~~~~~~~~~~charles@work
sally@nasa~~~~~~~~~sally@mars
sally@nasa~~~~~~~~~sally@gmail
sally@nasa~~~~~~~~~ripley@nostromo
预期结果是从两个表中返回以下缺失记录:
bob@test~~~~~~~~~~~chuck@aol
sally@nasa~~~~~~~~~ripley@nostromo
请注意,chris@*
块是完全匹配的,因为无论哪个地址被视为主要地址,所有别名(加上主要)的总和仍然相同。哪个地址是主地址并不重要,因为整个主组的总和包含两个表中的所有条目。
我不介意这是否在 A->B 和 B->A 两个通道中运行,但我无法理解解决方案。
任何帮助表示赞赏:)
【问题讨论】:
对不起,但是随着栏目内容的翻转,我真的无法弄清楚这里的真正要求。您能否就您正在寻找的内容添加更多细节,或者改写一下? (“Primary”和“Sum”的使用让我特别困惑。) “总和”是指对每个主地址的所有行进行分组,选择所有地址,然后比较不同的结果。在我上面的示例中,两个表中的“chris”记录被认为是相同的,因为它们有 4 行,当它们组合在一个列表中并删除重复项时,会产生相同的 5 个电子邮件地址。 如果存在“重叠”值,需要做什么?例如,如果我们在表 A 中添加 ("bob@test", "c@work"),“bob”和“chris”块现在是否会被视为一个块? 这不可能发生:“好消息是地址不会在“AliasAddress”列中出现两次。” 【参考方案1】:drop TABLE #TABLEA
CREATE TABLE #TABLEA
([PrimaryAddress] varchar(10), [AliasAdress] varchar(12))
;
INSERT INTO #TABLEA
([PrimaryAddress], [AliasAdress])
VALUES
('chris@work', 'chris@home'),
('chris@work', 'c@work'),
('chris@work', 'theboss@work'),
('chris@work', 'thatguy@aol'),
('bob@test', 'test1@test'),
('bob@test', 'charles@work'),
('bob@test', 'chuck@aol'),
('sally@mars', 'sally@nasa'),
('sally@mars', 'sally@gmail')
;
drop TABLE #TABLEB
CREATE TABLE #TABLEB
([PrimaryAddress] varchar(10), [AliasAdress] varchar(15))
;
INSERT INTO #TABLEB
([PrimaryAddress], [AliasAdress])
VALUES
('chris@home', 'chris@work'),
('chris@home', 'c@work'),
('chris@home', 'theboss@work'),
('chris@home', 'thatguy@aol'),
('bob@test', 'test1@test'),
('bob@test', 'charles@work'),
('sally@nasa', 'sally@mars'),
('sally@nasa', 'sally@gmail'),
('sally@nasa', 'ripley@nostromo')
;
试试下面的
select a.PrimaryAddress,a.AliasAdress from #TABLEA a left join #TABLEB b on a.AliasAdress=b.AliasAdress or b.PrimaryAddress=a.AliasAdress
where b.PrimaryAddress is null
union all
select a.PrimaryAddress,a.AliasAdress from #TABLEB a left join #TABLEA b on a.AliasAdress=b.AliasAdress or b.PrimaryAddress=a.AliasAdress
where b.PrimaryAddress is null
【讨论】:
【参考方案2】:因此,您想比较表 A 和 B,并在任一表中查找不匹配的行。 outer join 怎么样,然后查找 NULL 值:
SELECT ta.*, tb.*
FROM table_a ta
FULL OUTER JOIN table_b tb ON tb.PrimaryAddress = ta.PrimaryAddress
AND tb.AliasAddress = ta.AliasAddress
WHERE ta.PrimaryAddress IS NULL
OR tb.PrimaryAddress IS NULL
如果我正确理解了这个问题,这应该会返回您所要求的内容。
【讨论】:
不幸的是。请注意,以这种方式匹配的行非常少。这是该查询的结果:chris@work chris@home NULL NULL chris@work c@work NULL NULL chris@work theboss@work NULL NULL chris@work thatguy@aol NULL NULL bob@test chuck@aol NULL NULL sally@mars sally@nasa NULL NULL sally@mars sally@gmail NULL NULL NULL NULL chris@home chris@work NULL NULL chris@home c@work NULL NULL chris@home theboss@work NULL NULL chris@home thatguy@aol NULL NULL sally@nasa sally@mars NULL NULL sally@nasa sally@gmail NULL NULL sally@nasa ripley@nostromo
那我不太确定你想要什么。上面的查询只返回表 a 或表 b 唯一的所有条目。在没有任何其他信息的情况下,这是(据我所知)识别新条目的唯一方法。【参考方案3】:
我是这样做的,最后有点举手之劳。
第一步,确定要比较的项目集。这是:
对于“主”值,在 Alias 中找到的所有值 也包括“主要”值(以涵盖 nasa/nostromo 案例)表(A 或 B)中的集合由其主值标识。真正让它变得困难的是,两个表(sally@mars、sally@nasa)之间没有共享主要值。所以我们可以比较集合,但我们必须能够分别“返回”到每张桌子上的主桌子(例如,从桌子 B 中脱颖而出的可能是 sally@nasa / ripley@nostroomo,但我们必须添加 sally@ mars / ripley@nostromo 到表 A)
如果在表中,主值显示为不同主值的别名(例如,在表 A 中,chris@work 显示为 bob@test 的别名),则会出现主要问题。为了理智起见,我假设这不会发生……但如果发生了,问题就会变得更加困难。
此查询用于在 B 中添加不在 A 中的缺失项,其中 A 和 B 的 PrimaryAddress 相同:
;WITH setA (SetId, FullSet)
as (-- Complete sets in A
select PrimaryAddress, AliasAdress
from A
union select PrimaryAddress, PrimaryAddress
from A
)
,setB (SetId, FullSet)
as (-- Complete sets in B
select PrimaryAddress, AliasAdress
from B
union select PrimaryAddress, PrimaryAddress
from B
)
,NotInB (Missing)
as (-- What's in A that's not in B
select FullSet
from setA
except select FullSet -- This is the secret sauce. Definitely worth your time to read up on how EXCEPT works.
from setB
)
-- Take the missing values plus their primaries from A and load them into B
INSERT B (PrimaryAddress, AliasAdress)
select A.PrimaryAddress, nB.Missing
from NotInB nB
inner join A
on A.AliasAdress = nb.Missing
将表格反转(从“NotInB”开始)再次运行它,以对 A 执行相同操作。
但是
对“in B not in A”的样本数据执行此操作会将 (sally@nasa, ripley@nostromo) 添加到 A,并且由于这是不同的主要数据,它会创建一个新集合,因此不会解决这个问题。它很快变得丑陋。从这里说出来:
通过两次,一次为 A 不在 B 中,一次为 B 不在 A 中 每次通过,必须做两次检查 首先检查上面的内容:主地址匹配的A中不是B中的内容,并添加它 第二次检查很难看:A 中的内容不在 B 中,其中来自 A 的主地址不是 B 中的主地址,因此必须是别名。在这里,在 B 的别名列表中找到 A 的主地址,在 B 中获取用于该集合的主键,并使用这些值在 B 中创建行。【讨论】:
【参考方案4】:好的,我们就是这样做的……因为它变得很痛苦,我们运行了一个程序,将每个条目的主地址添加为别名:xx@xx -> xx@xx,以便 所有的地址都被列为每个用户的别名。这类似于@Phillip Kelly 上面所做的。然后我们运行了以下代码:(虽然很乱,但它可以工作;也可以一次性完成)
SELECT 'Missing from B:' as Reason, TableA.[primary] as APrimary, TableA.[alias] as AAlias, TableB.[primary] as BPrimary,TableB.[alias] as BAlias into #A FROM dbo.TableA LEFT OUTER JOIN TableB ON TableB.alias = TableA.alias
SELECT 'Missing from A:' as Reason,TableA.[primary] as APrimary, TableA.[alias] as AAlias, TableB.[primary] as BPrimary,TableB.[alias] as BAlias into #B FROM dbo.TableB LEFT OUTER JOIN TableA ON TableA.alias = TableB.alias
select * from #A
select * from #B
UPDATE #A
SET #A.APrimary = #B.BPrimary
FROM #B INNER JOIN #A ON #A.APrimary = #B.BPrimary
WHERE #A.BPrimary IS NULL
UPDATE #B
SET #B.BPrimary = #A.APrimary
FROM #B INNER JOIN #A ON #B.BPrimary = #A.BPrimary
WHERE #B.APrimary IS NULL
select * from #A
select * from #B
select * into #result from (
select Reason, BPrimary as [primary], BAlias as [alias] from #B where APrimary IS NULL
union
select Reason, APrimary as [primary], AAlias as [alias] from #A where BPrimary IS NULL
) as tmp
select * from #result
drop table #A
drop table #B
drop table #result
GO
【讨论】:
以上是关于比较两个表中的主要/别名组的主要内容,如果未能解决你的问题,请参考以下文章