2013-07-12 86 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 |