查询从不同的表中选择不同的值,而不是重复它们(将它们显示为平面文件)

时间:2013-10-02 19:07:31

标签: sql sql-server

我正在尝试为一个人获取所有手机,电子邮件和组织,并以平面文件格式显示它。应该有n行,其中n是组织,电子邮件或电话的最大数量。一旦所有值都显示在行中,将显示NULL值,其中NULL是最后的值。电子邮件和电话每人只能有1个PreferredInd。我希望这些行在同一行(其中1个可以为NULL)。我试图在更复杂的查询上执行此操作,但无法使其工作,所以我开始使用这个更简单的示例。

示例表和值:

@ContactPerson
Id        Name
1        John Doe

@ContactEmail
Id   PersonId     Email            PreferredInd
1    1            johndoe@us.gov     0
2    1            jdoe@us.gov        1
3    1            johndoe@gmail.com  0

@ContactPhone
Id   PersonId     Phone            PreferredInd
1    1            888-867-5309       0
2    1            305-476-5234       1

@ContactOrganization
Id   PersonId     Organization
1    1            US Government
2    1            US Army

我希望结果集看起来像:

Name           Organization    PreferredInd  Email             Phone
John Doe       US Government   1            jdoe@us.gov        888-867-5309
John Doe       US Army         0            johndoe@us.gov     305-467-5234
John Doe       NULL            0            johndoe@gmail.com  NULL



我对此示例的完整SQL代码是here on pastebin.它还包括用于创建示例表的代码。它适用于电子邮件数量超过组织或电话数量的情况,但并非总是如此。我似乎无法弄清楚如何获得我正在寻找的结果。我正在使用的实际表格可以包含每人0或无限的电子邮件,电话或组织。还会有更多的价值观,但我可以自己修复。

您可以帮我修改一下我的查询或向我展示一种更简单的方法吗?如果您有任何疑问,请告诉我,我可以尝试回答。

2 个答案:

答案 0 :(得分:4)

这样的事情?

with cte_e as (
    select
        *,
        row_number() over(order by PreferredInd desc, Id) as rn
    from ContactEmail
), cte_p as (
    select
        *,
        row_number() over(order by PreferredInd desc, Id) as rn
    from ContactPhone
), cte_o as (
    select
        *,
        row_number() over(order by Organization) as rn
    from ContactOrganization
), cte_d as (
    select distinct rn, PersonId from cte_e union
    select distinct rn, PersonId from cte_p union
    select distinct rn, PersonId from cte_o
)
select
    pr.Name, o.Organization, e.Email, p.Phone
from cte_d as d
    left outer join ContactPerson as pr on pr.Id = d.PersonId
    left outer join cte_e as e on e.PersonId = d.PersonId and e.rn = d.rn
    left outer join cte_p as p on p.PersonId = d.PersonId and p.rn = d.rn
    left outer join cte_o as o on o.PersonId = d.PersonId and o.rn = d.rn

<强> sql fiddle demo

它有点笨拙,我可以想到其他几种可能的方法来做到这一点,但我认为这个是最可读的方法

答案 1 :(得分:0)

第1步

编写一个查询,完成所有表的完全连接,最终会为每个人(每个电子邮件或电话号码)提供大量重复行

第2步 编写第二个使用GroupBy对行进行分组的查询,并使用Case或Decode关键字(如c#switch语句)查找首选行值并选择它作为要显示的值