SQL联盟但过滤掉部分重复项

时间:2016-09-06 11:04:59

标签: sql sql-server join union

这是我所拥有的非常简化的版本。

我有2个数据库表人员和联系人。 People是原始表,但contacts是一个新表,用于覆盖People表中的数据(这些是真实场景中的不同数据库)

在初始加载时,所有人员记录都会复制到联系人表格,但在初始加载后,新人员可以添加到人员或联系人表格以及设置为已删除的联系人。

我希望所有人都返回,但我希望联系人表格是最重要的,例如

例如

人员表

     PersonGuid | PersonId | FirstName   | LastName
     -----------|----------|-------------|-----
1      xxxx1    | 1        | John        | Smith
2      xxxx2    | 2        | Jane        | Doe
3      xxxx3    | 3        | John        | Doe
4      xxxx4    | 4        | Alice       | James
5      xxxx5    | 5        | Claire      | Wheeler

通讯录表 (Jane Doe设置为已删除,John Doe不存在,因为在初始导入和添加了Emma Green之后添加了。对于尚未触及的内容,已删除为NULL)

     ID         | LinkedId | FirstName   | LastName |  Deleted
     -----------|----------|-------------|----------|----------
1      xxxx1    | 1        | John        | Smith    |  NULL
2      xxxx2    | 2        | Jane        | Doe      |  1
3      xxxx3    | NULL     | Emma        | Green    |  0
4      xxxx4    | 4        | Alice       | James    |  0
5      xxxx5    | 5        | Claire      | Wheeler  |  NULL

我要返回的内容是:(所有记录,但Jane Doe设置为已删除,因为她在联系人表格中)

     ID         | LinkedId | FirstName   | LastName |  Deleted
     -----------|----------|-------------|----------|----------
1      xxxx1    | 1        | John        | Smith    |  NULL
2      xxxx2    | 2        | Jane        | Doe      |  1
3      xxxx3    | 3        | John        | Doe      |  0
4      xxxx4    | NULL     | Emma        | Green    |  0
5      xxxx5    | 4        | Alice       | James    |  0
6      xxxx6    | 5        | Claire      | Wheeler  |  NULL

但我得到的是: (Jane Doe Twice)

     ID         | LinkedId | FirstName   | LastName |  Deleted
     -----------|----------|-------------|----------|----------
1      xxxx1    | 1        | John        | Smith    |  NULL
2      xxxx2    | 2        | Jane        | Doe      |  1
3      xxxx2    | 2        | Jane        | Doe      |  0
4      xxxx3    | 3        | John        | Doe      |  0
5      xxxx4    | NULL     | Emma        | Green    |  0
6      xxxx5    | 4        | Alice       | James    |  0
7      xxxx6    | 5        | Claire      | Wheeler  |  NULL

我正在尝试联合这两个表,但我不知道如何过滤它以使联系人数据覆盖人员数据,但也从两个表中获取所有数据?

Select PersonGuid as Id,
Personid,
Firstname,
LastName,
cast(0 as bit) as deleted
From DB1.People

Union

Select
Id,
LinkedId as PersonId,
FirstName,
LastName,
Deleted 
from DB2.Contacts

我尝试过搜索,但我不确定要搜索什么,所以我的用语可能不对。

编辑 - 真正的查询并不像我的例子那么简单,而且from是每个查询大约6个表的连接。我试图用一个简单的例子说清楚,但不确定这是否使解决方案有所不同?

5 个答案:

答案 0 :(得分:0)

尝试使用以下查询。

Select PersonGuid as Id,
Personid,
Firstname,
LastName,
cast(0 as bit) as deleted
From DB1.People
where not exists (select 1 from Contacts WHERE personID=LinkedId and deleted=1)

Union

Select
Id,
LinkedId as PersonId,
FirstName,
LastName,
Deleted 
from DB2.Contacts

答案 1 :(得分:0)

看起来你不想要一个联盟 - 而是你想要一个联盟。 FULL OUTER JOIN返回两个表的所有行,并允许您通过加入ID和LinkedID来识别同一个人的行。

然后,如果存在行,您可以使用ISNULL函数从“联系人”中进行选择,如果不存在,则可以选择“人员”。

Select ISNULL(C.ID,P.PersonGuid) as Id,
       ISNULL(C.LinkedID,Personid) as PersonId,
       ISNULL(C.Firstname,P.FirstName) as FirstName,
       ISNULL(C.Lastname,P.Lastname) as LastName,
       ISNULL(C.Deleted,cast(0 as bit)) as deleted
From DB1.People P
FULL OUTER JOIN DB2.Contacts C on P.PersonID = C.LinkedId

答案 2 :(得分:0)

我认为这可能会做你想要的:

select pc.*
from (select pc.*,
             row_number() over (partition by firstname, lastname order by priority) as seqnum
from ((select ID, LinkedId, FirstName, LastName, Deleted, 1 as priority
             from contacts
            ) union all
            (select PersonGuid, PersonId, FirstName, LastName, 0 as Deleted, 2
             from persons
            )
           ) pc
     ) pc
where seqnum = 1;

我不确定你是如何在桌子上识别同一个人的。这使用名称,因为这就是你用文字描述问题的方式。

这个想法如下:

  • 使用UNION ALL(不是UNION)合并所有表格中的行。
  • 添加优先级列。
  • 使用ROW_NUMBER()根据优先级选择第一个值(PARTITION BY如果您使用的话会更改,例如,表之间的ID匹配。)
  • 最后,选择行号为1的行。

答案 3 :(得分:0)

请你试试这个:

SELECT p.PersonGuid, 
    p.PersonId, 
    p.FirstName, 
    p.LastName, 
    CASE WHEN c.LinkedId IS NULL THEN 0 ELSE c.DELETED END deleted 
FROM people p
LEFT JOIN contact c ON c.LinkedId = p.PersonId
UNION
SELECT * FROM #contact a WHERE a.LinkedId IS NULL

答案 4 :(得分:-1)

UNION会为您提供没有重复的记录,因此要使用联系人覆盖人员数据,请更改查询的顺序:

Select Id, LinkedId as PersonId, FirstName, LastName, Deleted 
from DB2.Contacts

UNION

Select PersonGuid as Id,Personid,Firstname,LastName,cast(0 as bit) as deleted 
From DB1.People

要获取所有记录,请使用UNION ALL代替UNION。这也将返回重复项。