非规范化SQL Server表

时间:2013-11-09 19:59:42

标签: sql-server denormalization

我有两个规范化的 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, 'john@hotmail.com')
insert into Email values (1, 'john@gmail.com')
insert into Email values (1, 'john.smith@hotmail.com')
insert into Email values (2, 'mary@hotmail.com')
insert into Email values (3, 'phill@hotmail.com')
insert into Email values (3, 'phill@gmail.com')
insert into Email values (3, 'taylor.phill@hotmail.com')
insert into Email values (3, 'taylor.phill@gmail.com')
go

当我加入这些表时,我有几行,只有一行电子邮件:

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


NAME            EMAIL
-------------   --------------------------
JOHN SMITH      john@hotmail.com
JOHN SMITH      john@gmail.com
JOHN SMITH      john.smith@hotmail.com
MARY SMITH      mary@hotmail.com
PHILL TAYLOR    phill@hotmail.com
PHILL TAYLOR    phill@gmail.com
PHILL TAYLOR    taylor.phill@hotmail.com
PHILL TAYLOR    taylor.phill@gmail.com

但我需要在同一行中放置所有电子邮件以满足预定义的布局:

NAME            EMAIL1              EMAIL2          EMAIL3                      EMAIL4
-------------   -----------------   --------------- -----------------------     -----------------
JOHN SMITH      john@hotmail.com    john@gmail.com  john.smith@hotmail.com
MARY SMITH      mary@hotmail.com
PHILL TAYLOR    phill@hotmail.com   phill@gmail.com taylor.phill@hotmail.com    taylor.phill@hotmail.com

是否可以使用单个选择?

任何想法都会非常感激

TIA

Ricardo Nogueira

2 个答案:

答案 0 :(得分:2)

可以在1个选择中完成。如果您只想要前4个电子邮件地址并将其用作特定列。使用电子邮件表上的RowNumber函数为每个用户的mailaddresses编号。此示例假定电子邮件地址应按字母顺序排序:

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)

答案 1 :(得分:0)

它不漂亮并且有使用问题等等但是如果你必须......你必须..所以,使用你的架构,这个: -

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    john.smith@hotmail.com  john@gmail.com     john@hotmail.com        NULL
MARY SMITH    mary@hotmail.com        NULL               NULL                    NULL
PHILL TAYLOR  phill@gmail.com         phill@hotmail.com  taylor.phill@gmail.com  taylor.phill@hotmail.com