2013-05-07 3 views
3

Я работаю с SQL Server 2008 R2.Сглаживание нормализованной базы данных SQL Server 2008 R2

У меня есть 3 стола, данные нормализованы, и я ищу, чтобы захватить телефон «Дом» и «Сотовый» для Боба Доула. Однако мне нужно получить только номер телефона с наивысшим номером каждого типа. (Ниже приведен пример Боб Доул, имеющие 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 

Таблица НомерТелефон

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

Таблица PhoneNumberType

PhoneNumberTypeId  PhoneNumberType 
1      Home 
2      Cell 

Мой желаемый результат будет (обратите внимание, что я вернулся только первый номер сотового.):

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

У меня были проблемы, уплощение данные

Любая помощь с запросом будет будь здорово!

+1

Что такое бизнес-правило, определяющее, что вы выбрали номер ячейки 222, а не номер ячейки 333 в приведенном выше примере? –

+0

Бизнес-правило заключается в том, что пользовательский интерфейс позволяет пользователю назначать порядок последовательности. Таким образом, пользователь установил последовательность для 222-222-2222 как «2», а последовательность для 333-333-3333 - «3». Мы разрешаем пользователям перетаскивать или удалять телефонные номера на экране, эффективно определяя приоритет этих номеров. – Princess

+0

Как в стороне, я думаю, что 'PhoneNumberTypeId' должен принадлежать таблице' PhoneNumber'. Или было бы целесообразно знать тип номера телефона, не зная самого номера? Или другой пример: если более одного человека разделили один и тот же номер, почему вы хотите указать тип номера для каждого из людей? –

ответ

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

2

Вот пример с подзапросом для получения первого порядкового номера для каждого типа. Затем внешний запрос использует оператор CASE для создания столбцов Home и Cell.

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