TSQL透过可变长度子查询

时间:2017-09-05 21:02:15

标签: sql-server

给出表格

Country
ID    Name
1     USA
2     Canada
3     Australia

Territory
ID    CountryID     Name
1     1             Michigan
2     1             Colorado
3     1             Iowa
4     2             Manitoba
5     2             Quebec
6     2             Saskatchewan
7     2             Alberta
8     3             Queensland
9     3             Victoria

SubDivisions
ID     TerritoryID   Name
1      8             Stanley
2      8             Ward
3      8             Canning
4      9             Bourke
5      9             Dalhousie
6      9             Grant
7      1             Washtenaw
8      1             Alpena
9      2             Baca
10     2             Delta
11     2             Doug
12     3             Adams
13     3             Fayette
14     3             Decatur
15     3             Hancock
16     4             Eastman
17     4             Interlake
18     5             Estrie
19     5             Montreal
20     5             Cote-Nord
21     5             Bas-Saint-Laurent
22     6             Kootenays
23     6             Okanagan
24     6             Thompson
25     7             Athabasca
26     7             MacKenzie
27     7             Saddle Hills

我无法使用生成此类(国家,地区)输出的数据透视表创建查询:

Australia   Queensland    Canning            Stanley    Ward
Australia   Victoria      Bourke             Dalhousie  Grant
Canada      Alberta       Athabasca          MacKenzie  Saddle Hills
Canada      Manitoba      Eastman            Interlake
Canada      Quebec        Bas-Saint-Laurent  Cote-Nord  Estrie        Montreal
Canada      Saskatchewan  Kootenays          Okanagan   Thompson
USA         Colorado      Baca               Delta      Doug
USA         Iowa          Adams              Decatur    Fayette       Hancock
USA         Michigan      Alpena             Washtenaw`

订购所有物品都是一种魅力,并非严格要求。我知道如何用光标做到这一点,但刚刚学习了Pivot,我正在寻找更好的方法。此外,Pivot似乎想要某种聚合函数,我不需要该值,但在结果集中很容易忽略它。

TIA

此外,为方便起见,以下SQL脚本将创建并填充我描述的测试表:

Create Table Country
    (ID int, Name VarChar(50))
Go

Insert Country (ID,Name)
Values (1,'USA')
Insert Country (ID,Name)
Values (2,'Canada')
Insert Country (ID,Name)
Values (3,'Australia')
Go

Create Table Territory
    (ID int, CountryID int, Name VarChar(50))
Go

Insert Territory (ID,CountryID,Name)
Values (1,1,'Michigan')
Insert Territory (ID,CountryID,Name)
Values (2,1,'Colorado')
Insert Territory (ID,CountryID,Name)
Values (3,1,'Iowa')
Insert Territory (ID,CountryID,Name)
Values (4,2,'Manitoba')
Insert Territory (ID,CountryID,Name)
Values (5,2,'Quebec')
Insert Territory (ID,CountryID,Name)
Values (6,2,'Saskatchewan')
Insert Territory (ID,CountryID,Name)
Values (7,2,'Alberta')
Insert Territory (ID,CountryID,Name)
Values (8,3,'Queensland')
Insert Territory (ID,CountryID,Name)
Values (9,3,'Victoria')
Go

Create Table SubDivisions
    (ID int, TerritoryID int, Name VarChar(50))
Go

Insert SubDivisions (ID, TerritoryID, Name)
Values (1, 8, 'Stanley')
Insert SubDivisions (ID, TerritoryID, Name)
Values (2, 8, 'Ward')
Insert SubDivisions (ID, TerritoryID, Name)
Values (3, 8, 'Canning')
Insert SubDivisions (ID, TerritoryID, Name)
Values (4, 9, 'Bourke')
Insert SubDivisions (ID, TerritoryID, Name)
Values (5, 9, 'Dalhousie')
Insert SubDivisions (ID, TerritoryID, Name)
Values (6, 9, 'Grant')
Insert SubDivisions (ID, TerritoryID, Name)
Values (7, 1, 'Washtenaw')
Insert SubDivisions (ID, TerritoryID, Name)
Values (8, 1, 'Alpena')
Insert SubDivisions (ID, TerritoryID, Name)
Values (9, 2, 'Baca')
Insert SubDivisions (ID, TerritoryID, Name)
Values (10, 2, 'Delta')
Insert SubDivisions (ID, TerritoryID, Name)
Values (11, 2, 'Doug')
Insert SubDivisions (ID, TerritoryID, Name)
Values (12, 3, 'Adams')
Insert SubDivisions (ID, TerritoryID, Name)
Values (13, 3, 'Fayette')
Insert SubDivisions (ID, TerritoryID, Name)
Values (14, 3, 'Decatur')
Insert SubDivisions (ID, TerritoryID, Name)
Values (15, 3, 'Hancock')
Insert SubDivisions (ID, TerritoryID, Name)
Values (16, 4, 'Eastman')
Insert SubDivisions (ID, TerritoryID, Name)
Values (17, 4, 'Interlake')
Insert SubDivisions (ID, TerritoryID, Name)
Values (18, 5, 'Estrie')
Insert SubDivisions (ID, TerritoryID, Name)
Values (19, 5, 'Montreal')
Insert SubDivisions (ID, TerritoryID, Name)
Values (20, 5, 'Cote-Nord')
Insert SubDivisions (ID, TerritoryID, Name)
Values (21, 5, 'Bas-Saint-Laurent')
Insert SubDivisions (ID, TerritoryID, Name)
Values (22, 6, 'Kootenays')
Insert SubDivisions (ID, TerritoryID, Name)
Values (23, 6, 'Okanagan')
Insert SubDivisions (ID, TerritoryID, Name)
Values (24, 6, 'Thompson')
Insert SubDivisions (ID, TerritoryID, Name)
Values (25, 7, 'Athabasca')
Insert SubDivisions (ID, TerritoryID, Name)
Values (26, 7, 'MacKenzie')
Insert SubDivisions (ID, TerritoryID, Name)
Values (27, 7, 'Saddle Hills')
Go

1 个答案:

答案 0 :(得分:0)

试试这个SQL(需要SQL Server 2012 +)

select
     t.CountryName
    ,t.TerritoryName
    ,Col1 = max(Col1)
    ,Col2 = max(Col2)
    ,Col3 = max(Col3)
    ,Col4 = max(Col4)
    ,Col5 = max(Col5)
    ,Col6 = max(Col6)
    ,Col7 = max(Col7)
    ,Col8 = max(Col8)
from (
    select
         CountryName        = Country.Name
        ,TerritoryName      = Territory.Name
        ,SubDivisionsName   = SubDivisions.Name
        ,ColNo = row_number() over (partition by Country.Name,Territory.Name
                                    order by SubDivisions.Name)
    from Country
    join Territory     on Territory.CountryID       = Country.ID
    join SubDivisions  on SubDivisions.TerritoryID  = Territory.ID
) data
cross apply (values
     (CountryName, TerritoryName, 1, SubDivisionsName, '', '', '', '', '', '', '')
    ,(CountryName, TerritoryName, 2, '', SubDivisionsName, '', '', '', '', '', '')
    ,(CountryName, TerritoryName, 3, '', '', SubDivisionsName, '', '', '', '', '')
    ,(CountryName, TerritoryName, 4, '', '', '', SubDivisionsName, '', '', '', '')
    ,(CountryName, TerritoryName, 5, '', '', '', '', SubDivisionsName, '', '', '')
    ,(CountryName, TerritoryName, 6, '', '', '', '', '', SubDivisionsName, '', '')
    ,(CountryName, TerritoryName, 7, '', '', '', '', '', '', SubDivisionsName, '')
    ,(CountryName, TerritoryName, 8, '', '', '', '', '', '', '', SubDivisionsName)
) t(CountryName, TerritoryName, ColNo, Col1, Col2, Col3, Col4, Col5, Col6, Col7, Col8)
where t.CountryName     = data.CountryName
  and t.TerritoryName   = data.TerritoryName
  and t.ColNo = data.ColNo
group by
     t.CountryName
    ,t.TerritoryName
order by
     t.CountryName
    ,t.TerritoryName

将产生所需的输出:

enter image description here

请特别注意valuesclause cross apply的使用以及交叉应用本身。 交叉申请也有类似于外部加入的风格;适当地称为外部申请