2013-07-12 80 views
1

我有一个问题,可视化地址信息。如何从3个表创建数据透视表?

  • 我有1人或关系具有更多然后1个ADRESS。
  • 我存储在ADRESS表中的每个ADRESS并确定它是什么样的ADRESS的。
  • 我有3个地址类型为例。

我需要做的是将所有地址栏相邻的可视化。

如果我只有一个ADRESS,那么其他领域都显示NULL因为没有ADRESS。

在这里,我创建了一个小桌子设置。

Create table relation(
PKid int identity(1,1) primary key, 
Name varchar(255) 
) 

--Create table Adrestype(
PKid int identity(1,1) primary key, 
TypeDescription varchar(255) 
) 

Create table adres(
PKid int identity(1,1) primary key, 
Street varchar(255), 
Number varchar(255), 
zipcode varchar(255), 
Location varchar(255), 
AdresTypeId int 
) 

Create table RelationXAdres(
PKid int identity(1,1) primary key, 
RelationID int not null, 
adresID int not null 
) 

Insert into Relation values('Peter'); 
Insert into Relation values('Nico'); 
Insert into Relation values('Bart'); 
Insert into Relation values('Werner'); 

Insert into Adrestype values('Work'); 
Insert into Adrestype values('Home'); 
Insert into Adrestype values('Extra'); 

Insert into adres values ('Streetname', '125', '5520', 'Gent', 1) 
Insert into adres values ('StreetLane', '15', '5550', 'Rome', 2) 
Insert into adres values ('Street', '12', '5120', 'Paris', 3) 
Insert into RelationXAdres values(1,1); 
Insert into RelationXAdres values(1,2); 
Insert into RelationXAdres values(1,3); 

Insert into adres values ('againstraat', '5', '4420', 'Oslo', 1) 
Insert into adres values ('some Street', '12', '2220', 'Praag', 2) 
Insert into RelationXAdres values(2,4); 
Insert into RelationXAdres values(2,5); 

Insert into adres values ('SoloStreet', '5', '4420', 'Oslo', 1) 
Insert into RelationXAdres values(3,6); 

Insert into adres values ('MainStreet', '25', '1120', 'Berlin', 3) 
Insert into RelationXAdres values(4,7); 

-- show all tabel's data 
select * from relation 
Select * from adres 
select * from RelationXAdres 
select * from Adrestype 

-- Show all data in 1 statement 
select * from relation r 
left join RelationXAdres ra on ra.RelationID = r.PKid 
left join adres a on a.PKid = ra.adresId 
left join adrestype at on at.PKid = a.AdresTypeId 

这是个什么结果有看起来像:

enter image description here

回答

2

由于您使用的SQL Server有几种方法,你可以透视的数据行成列。

可以使用聚合函数CASE表达式:

select r.pkid, 
    r.name, 
    max(case when at.typedescription = 'home' then a.street end) homestreet, 
    max(case when at.typedescription = 'home' then a.number end) homeNumber, 
    max(case when at.typedescription = 'home' then a.zipcode end) homezipcode, 
    max(case when at.typedescription = 'home' then a.location end) homelocation, 
    max(case when at.typedescription = 'work' then a.street end) workstreet, 
    max(case when at.typedescription = 'work' then a.number end) workNumber, 
    max(case when at.typedescription = 'work' then a.zipcode end) workzipcode, 
    max(case when at.typedescription = 'work' then a.location end) worklocation, 
    max(case when at.typedescription = 'extra' then a.street end) extrastreet, 
    max(case when at.typedescription = 'extra' then a.number end) extraNumber, 
    max(case when at.typedescription = 'extra' then a.zipcode end) extrazipcode, 
    max(case when at.typedescription = 'extra' then a.location end) extralocation 
from relation r 
left join RelationXAdres ra 
    on r.pkid = ra.RelationID 
left join adres a 
    on ra.adresid = a.pkid 
left join adrestype at 
    on a.AdresTypeId = at.PKid 
group by r.pkid, r.name; 

SQL Fiddle with Demo

你可以同时应用UNPIVOTPIVOT功能。该UNPIVOT功能将采取的streetnumberzipcodelocation你多列,并将其转换为多行。

select pkid, name, 
    col = typeDescription+col, 
    value 
from 
(
    select r.pkid, 
    r.name, 
    at.typedescription, 
    a.street, 
    a.number, 
    a.zipcode, 
    a.location 
    from relation r 
    left join RelationXAdres ra 
    on r.pkid = ra.RelationID 
    left join adres a 
    on ra.adresid = a.pkid 
    left join adrestype at 
    on a.AdresTypeId = at.PKid 
) d 
unpivot 
(
    value 
    for col in (street, number, zipcode, location) 
) unpiv; 

请参阅SQL Fiddle with Demo。这使多行的结果:

| PKID | NAME |   COL |  VALUE | 
----------------------------------------------- 
| 1 | Peter | Workstreet | Streetname | 
| 1 | Peter | Worknumber |   125 | 
| 1 | Peter | Workzipcode |  5520 | 
| 1 | Peter | Worklocation |  Gent | 
| 1 | Peter | Homestreet | StreetLane | 
| 1 | Peter | Homenumber |   15 | 

一旦数据在多行,那么你可以申请的旋转功能:

;with cte as 
(
    select pkid, name, 
    col = typeDescription+col, 
    value 
    from 
    (
    select r.pkid, 
     r.name, 
     at.typedescription, 
     a.street, 
     a.number, 
     a.zipcode, 
     a.location 
    from relation r 
    left join RelationXAdres ra 
     on r.pkid = ra.RelationID 
    left join adres a 
     on ra.adresid = a.pkid 
    left join adrestype at 
     on a.AdresTypeId = at.PKid 
) d 
    unpivot 
    (
    value 
    for col in (street, number, zipcode, location) 
) unpiv 
) 
select pkid, name, 
    homestreet, homenumber, homezipcode, homelocation, 
    workstreet, worknumber, workzipcode, worklocation, 
    extrastreet, extranumber, extrazipcode, extralocation 
from cte 
pivot 
(
    max(value) 
    for col in (homestreet, homenumber, homezipcode, homelocation, 
       workstreet, worknumber, workzipcode, worklocation, 
       extrastreet, extranumber, extrazipcode, extralocation) 
) p; 

SQL Fiddle with Demo

以上版本将工作的伟大,如果你有一个已知的数列,但如果你有一个未知的数值(地址类型),那么你将要使用动态SQL:

DECLARE @cols AS NVARCHAR(MAX), 
    @query AS NVARCHAR(MAX) 

select @cols = STUFF((SELECT ',' + QUOTENAME(a.TypeDescription+c.col) 
        from Adrestype a 
        cross apply 
        (
         select 'street', 1 union all 
         select 'number', 2 union all 
         select 'zipcode', 3 union all 
         select 'location', 4 
        ) c (col, so) 
        group by a.TypeDescription, c.col, c.so 
        order by case a.TypeDescription 
           when 'home' then 1 
           when 'work' then 2 
           when 'extra' then 3 end, c.so 
      FOR XML PATH(''), TYPE 
      ).value('.', 'NVARCHAR(MAX)') 
     ,1,1,'') 

set @query = 'SELECT pkid, name, ' + @cols + ' 
      from 
      (
       select pkid, name, 
        col = typeDescription+col, 
        value 
       from 
       (
        select r.pkid, 
        r.name, 
        at.typedescription, 
        a.street, 
        a.number, 
        a.zipcode, 
        a.location 
        from relation r 
        left join RelationXAdres ra 
        on r.pkid = ra.RelationID 
        left join adres a 
        on ra.adresid = a.pkid 
        left join adrestype at 
        on a.AdresTypeId = at.PKid 
       ) d 
       unpivot 
       (
        value 
        for col in (street, number, zipcode, location) 
       ) unpiv 
      ) x 
      pivot 
      (
       max(value) 
       for col in (' + @cols + ') 
      ) p ' 

execute sp_executesql @query; 

SQL Fiddle with Demo。所有这些疑问的给一个结果:

| PKID | NAME | HOMESTREET | HOMENUMBER | HOMEZIPCODE | HOMELOCATION | WORKSTREET | WORKNUMBER | WORKZIPCODE | WORKLOCATION | EXTRASTREET | EXTRANUMBER | EXTRAZIPCODE | EXTRALOCATION | 
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- 
| 1 | Peter | StreetLane |   15 |  5550 |   Rome | Streetname |  125 |  5520 |   Gent |  Street |   12 |   5120 |   Paris | 
| 2 | Nico | some Street |   12 |  2220 |  Praag | againstraat |   5 |  4420 |   Oslo |  (null) |  (null) |  (null) |  (null) | 
| 3 | Bart |  (null) |  (null) |  (null) |  (null) | SoloStreet |   5 |  4420 |   Oslo |  (null) |  (null) |  (null) |  (null) | 
| 4 | Werner |  (null) |  (null) |  (null) |  (null) |  (null) |  (null) |  (null) |  (null) | MainStreet |   25 |   1120 |  Berlin |