SQL - 确保在一组关键密钥对中表示的两个实体都存在于最终数据集中的有效方法

Posted

技术标签:

【中文标题】SQL - 确保在一组关键密钥对中表示的两个实体都存在于最终数据集中的有效方法【英文标题】:SQL - Efficient way to make sure both entities represented in a set of key Keypairs exist in final dataset 【发布时间】:2016-06-09 16:11:37 【问题描述】:

问题:我如何有效地获取匹配为一组(下面的#Keys 表)的人员列表(下面的#People 表,每行一个人),但还要确保这些组是唯一的。

背景:我正在处理数据库中的匹配集(以 KeyId、PersonId1、PersonId2 的形式)。我们有一种自动方法,可以将人员标记为重复项并将其写入匹配表。没有太多,但我们通常会坐下来大约 100K 的比赛记录和 200K 的人。匹配过程还以匹配 Person 1 与 2 以及匹配 2 与 1 的形式添加重复记录。此外,我们在逻辑上删除人员记录 (IsDeleted = 1),因此不希望返回一个人已经存在的匹配项已删除。

我们有一个管理屏幕,人们可以在其中查看重复项并标记他们是否不是受骗者,或删除其中一个。出现了一个问题,即使其中一个人被删除,另一个人仍然显示在列表中。下面的 SQL 试图确保只返回作为集合存在的人。

测试数据设置:

CREATE TABLE #Keys
(
    KeyId int PRIMARY KEY,
    PersonId1 int,
    PersonId2 int
)

CREATE TABLE #People
(
    PersonId int PRIMARY KEY,
    Name varchar(150),
    IsDeleted bit
)

INSERT INTO #People
VALUES  (1, 'John',0),
        (2, 'Madeline',0),
        (3, 'Ralph',1),
        (4, 'Sarah',0),
        (5, 'Jack',0),
        (6, 'Olivia',0),
        (7, 'Ethan',0),
        (8, 'Sophia',0)

INSERT INTO #Keys
VALUES  (1,1,2),
        (2,2,3),
        (3,1,3),
        (4,2,1),
        (5,4,8),
        (6,3,7),
        (7,6,1)

SELECT *
FROM #Keys k
 JOIN #People p1
    ON k.PersonId1 = p1.PersonId
    AND p1.IsDeleted = 0
 JOIN #People p2
    ON k.PersonId2 = p2.PersonId
    AND p2.IsDeleted = 0

返回:

KeyId   PersonId1   PersonId2   PersonId    Name    IsDeleted   PersonId    Name    IsDeleted
1   1   2   1   John    0   2   Madeline    0
4   2   1   2   Madeline    0   1   John    0
5   4   8   4   Sarah   0   8   Sophia  0
7   6   1   6   Olivia  0   1   John    0



SELECT KeyId, p1.PersonId, p1.Name
INTO #Results
FROM #Keys k
 JOIN #People p1
    ON k.PersonId1 = p1.PersonId
    AND p1.IsDeleted = 0
 JOIN #People p2
    ON k.PersonId2 = p2.PersonId
    AND p2.IsDeleted = 0

INSERT INTO #Results
SELECT KeyId, p2.PersonId, p2.Name
FROM #Keys k
 JOIN #People p1
    ON k.PersonId1 = p1.PersonId
    AND p1.IsDeleted = 0
 JOIN #People p2
    ON k.PersonId2 = p2.PersonId
    AND p2.IsDeleted = 0

SELECT * from #Results
order by KeyId

DROP TABLE #People
DROP TABLE #Keys
DROP TABLE #Results

最终查询返回这个集合:

KeyId   PersonId    Name
1   2   Madeline
1   1   John
4   2   Madeline
4   1   John
5   8   Sophia
5   4   Sarah
7   6   Olivia
7   1   John

但是问题是1号和4号的人是一样的,只是顺序颠倒了。我想要返回的集合是:

KeyId   PersonId    Name
1   2   Madeline
1   1   John
5   4   Sarah
5   8   Sophia
7   1   John
7   6   Olivia

【问题讨论】:

您是否有理由不能根据键值对的唯一性进行约束?您必须确保您的应用程序代码可以通过***.com/questions/15800250/… 处理插入键值对的失败 【参考方案1】:

首先我会做

PersonId1 int,
PersonId2 int

#Keys 上的 PK 并删除 KeyId

快速获取独一无二的方法

select PersonId1, PersonId2 
from keys 
where PersonId1 < PersonId2 
union 
select PersonId2, PersonId1 
from keys 
where PersonId2 < PersonId1 

显然你需要在删除时添加加入

您还可以对 PersonId1 的#Keys 施加约束

我认为这也可行

select PersonId1, PersonId2 from keys 
except 
select PersonId2, PersonId1 from keys 

【讨论】:

我需要保留 KeyId 以在处理过程中显示下游人员之间的联系,但是使用您的方法,对 personIds 进行分组并获取 MAX(KeyId) 给了我我需要的唯一集.

以上是关于SQL - 确保在一组关键密钥对中表示的两个实体都存在于最终数据集中的有效方法的主要内容,如果未能解决你的问题,请参考以下文章

Ruby - 模型中表示的迁移参考

SQL中表的类型

如何将(r,球形谐波)空间中表示的数据内插到常规笛卡尔网格(F90)?

密钥列具有不同名称时实体拆分?

CoreData:在一次提取中返回一组与 nsnumber 索引数组匹配的实体

sql中表达完整性约束