Денормализация таблиц SQL Server

У меня есть две нормализованные таблицы SQL Server 2008, одна для имен, а другая для адресов электронной почты:

create table Name (NameId int, Name varchar(50))
create table Email (NameId int, Email varchar(50))
go

insert into Name values (1, 'JOHN SMITH')
insert into Name values (2, 'MARY SMITH')
insert into Name values (3, 'PHILL TAYLOR')
go

insert into Email values (1, '[email protected]')
insert into Email values (1, '[email protected]')
insert into Email values (1, '[email protected]')
insert into Email values (2, '[email protected]')
insert into Email values (3, '[email protected]')
insert into Email values (3, '[email protected]')
insert into Email values (3, '[email protected]')
insert into Email values (3, '[email protected]')
go

Когда я присоединяюсь к этим таблицам, у меня есть несколько строк, в которых содержится только одно электронное письмо:

Select name, email
from Name inner join Email on name.NameId=email.NameId


NAME            EMAIL
-------------   --------------------------
JOHN SMITH      [email protected]
JOHN SMITH      [email protected]
JOHN SMITH      [email protected]
MARY SMITH      [email protected]
PHILL TAYLOR    [email protected]
PHILL TAYLOR    [email protected]
PHILL TAYLOR    [email protected]
PHILL TAYLOR    [email protected]

Но мне нужно, чтобы все электронные письма были в одной строке, чтобы удовлетворить предопределенный макет:

NAME            EMAIL1              EMAIL2          EMAIL3                      EMAIL4
-------------   -----------------   --------------- -----------------------     -----------------
JOHN SMITH      [email protected]    [email protected]  [email protected]
MARY SMITH      [email protected]
PHILL TAYLOR    [email protected]   [email protected] [email protected]    [email protected]

Возможно ли использовать одиночный выбор?

Любые идеи будут очень признательны

ТИА

Рикардо Ногейра


person user2974686    schedule 09.11.2013    source источник
comment
Будут ли значения, разделенные запятыми, выполнять эту работу? Всё намного проще..   -  person Yosi Dahari    schedule 10.11.2013
comment
Вы предполагаете, что все, если имена одинаковы, то адреса электронной почты относятся к одному и тому же человеку? Это не соответствует действительности, если только вы не ограничиваете ее каким-то (неуказанным в вопросе) критерием.   -  person Andrew Morton    schedule 10.11.2013
comment
что вы подразумеваете под предопределенным макетом? Я имею в виду, каков ваш предопределенный макет? Подойдет ли список писем через запятую?   -  person M.Ali    schedule 10.11.2013
comment
Да, окончательное намерение состоит в том, чтобы экспортировать выборку в CVS, но макет определяет человека в строке со всеми его / ее электронными письмами рядом.   -  person user2974686    schedule 13.11.2013


Ответы (2)


Это можно сделать в 1 выбор. Если вам нужны только первые 4 адреса электронной почты и используйте их в качестве определенных столбцов. Используйте функцию RowNumber в таблице электронной почты, чтобы пронумеровать почтовые адреса для каждого пользователя. В этом примере предполагается, что адреса электронной почты должны быть отсортированы по алфавиту:

with m as (
  select 
    ROW_NUMBER() over (partition by nameId order by email) as Nr, 
    email.NameId, email.Email 
  from email
)
select 
  name.NameId, 
  name.Name, 
  m1.Email as Mail1,
  m2.Email as Mail2,
  m3.Email as Mail3,
  m4.Email as Mail4
from name
left join m m1 on (m1.Nr=1 and m1.NameId=name.NameId)
left join m m2 on (m2.Nr=2 and m2.NameId=name.NameId)
left join m m3 on (m3.Nr=3 and m3.NameId=name.NameId)
left join m m4 on (m4.Nr=4 and m4.NameId=name.NameId)
person user2970362    schedule 09.11.2013

Это не красиво и имеет проблемы с использованием и т. Д., Но если вам нужно ... вы должны ... Итак, используя вашу схему, это: -

create function dbo.emails(@NameId int, @Ordinal int)
returns varchar(1024)
as begin
    declare @returnValue varchar(1024)
    select @returnValue=email
    from (
        select 
            ROW_NUMBER() over (order by e.Email) as ordinal,
            e.Email
        from Email e
        where e.NameId=@NameId
    ) p1 
    where p1.ordinal=@Ordinal
    return @returnValue
end
go
select e.Name,
    dbo.emails(n.NameId,1) as email1,
    dbo.emails(n.NameId,2) as email2,
    dbo.emails(n.NameId,3) as email3,
    dbo.emails(n.NameId,4) as email4
from Name n
go

производит:-

Name          email1                  email2             email3                  email4
JOHN SMITH    [email protected]  [email protected]     [email protected]        NULL
MARY SMITH    [email protected]        NULL               NULL                    NULL
PHILL TAYLOR  [email protected]         [email protected]  [email protected]  [email protected]
person dav1dsm1th    schedule 09.11.2013
comment
Где в вопросе упоминается высокая производительность? Иногда приходится предлагать прагматичное решение. - person dav1dsm1th; 06.02.2016
comment
Для меня плохой дизайн базы данных не прагматичен. Пользователь user2970362 предложил практичное решение, которое также хорошо работает. То, как вы это реализуете, является точной парадигмой строки, мучительной проблемой производительности строки из-за плохого дизайна базы данных. - person George Mavritsakis; 06.02.2016