展平规范化的SQL Server 2008 R2数据库

时间:2013-05-07 20:13:59

标签: sql sql-server sql-server-2008-r2

我正在使用SQL Server 2008 R2。

我有3张桌子,数据已标准化,我正在寻找Bob Dole的'Home'和'Cell'手机。但是我只需要获得每种类型的最高序列电话号码。 (以下是Bob Dole有2部手机的例子,每部手机的序列号分别为2和3)

PersonPhoneNumber

PersonPhoneNumberId  Person      PhoneNumberId    PhoneNumberTypeId    Sequence
Guid - vvv           Bob Dole    Guid - A         1                    1
Guid - www           Bob Dole    Guid - B         2                    2
Guid - xxx           Bob Dole    Guid - C         2                    3

PhoneNumber

PhoneNumberId   Number
Guid - A        111-111-1111
Guid - B        222-222-2222
Guid - C        333-333-3333

PhoneNumberType

PhoneNumberTypeId     PhoneNumberType
1                     Home
2                     Cell

我想要的输出就是这个(注意我只返回了第一个Cell编号。):

Person      Home            Cell
Bob Dole    111-111-1111    222-222-2222

我一直在解决数据问题

对查询的任何帮助都会很棒!

2 个答案:

答案 0 :(得分:3)

您可以使用row_number()和带CASE表达式的聚合函数将数据从行转换为列:

select person,
  max(case when rn = 1 and PhoneNumberType = 'Home' then number end) home,
  max(case when rn = 1 and PhoneNumberType = 'Cell' then number end) cell
from
(
  select ppn.person, pn.number,
    pt.PhoneNumberType,
    row_number() over(partition by ppn.person, ppn.PhoneNumberTypeId
                      order by ppn.sequence) rn
  from PersonPhoneNumber ppn
  inner join PhoneNumber pn
    on ppn.PhoneNumberId = pn.PhoneNumberId
  inner join PhoneNumberType pt
    on ppn.PhoneNumberTypeId = pt.PhoneNumberTypeId
) d
group by person;

请参阅SQL Fiddle with Demo

这也可以使用PIVOT功能完成:

select person,
  home, 
  cell
from
(
  select ppn.person, pn.number,
    pt.PhoneNumberType,
    row_number() over(partition by ppn.person, ppn.PhoneNumberTypeId
                      order by ppn.sequence) rn
  from PersonPhoneNumber ppn
  inner join PhoneNumber pn
    on ppn.PhoneNumberId = pn.PhoneNumberId
  inner join PhoneNumberType pt
    on ppn.PhoneNumberTypeId = pt.PhoneNumberTypeId
) d
pivot
(
  max(number)
  for PhoneNumberType in (Home, Cell)
) piv
where rn = 1;

请参阅SQL Fiddle with Demo

答案 1 :(得分:2)

这是一个带有子查询的示例,用于获取每个Type的第一个序列号。然后外部查询使用CASE语句来创建Home和Cell Columns。

SELECT  P.Person
        ,MAX(CASE WHEN P.PhoneNumberTypeId = 1 THEN N.Number ELSE NULL END) AS Home
        ,MAX(CASE WHEN P.PhoneNumberTypeId = 2 THEN N.Number ELSE NULL END) AS Cell
FROM    PersonPhoneNumber P
INNER JOIN
        PhoneNumber N
ON      P.PhoneNumberId = N.PhoneNumberId 
INNER JOIN
        (
        SELECT  Person
                ,PhoneNumberTypeId
                ,MIN(Sequence) AS FIRST_NUM
        FROM    PersonPhoneNumber
        GROUP BY
                Person
                ,PhoneNumberTypeId        
        ) SQ1
ON      P.Person = SQ1.Person
AND     P.PhoneNumberTypeId = SQ1.PhoneNumberTypeId
AND     P.Sequence = SQ1.FIRST_NUM
GROUP BY
        P.PERSON