2014-09-23 64 views
1

我试图找到一个查询,可以动态地在多个级别生成交叉表输出。我确实在网上找到了几个可以返回动态交叉表结果的解决方案,但它只返回单一级别。下面是SQL小提琴:多级交叉表动态查询

CREATE TABLE dbo.PopulationDetails 
(
Country VARCHAR(50), 
State VARCHAR(50), 
Population BIGINT, 
SeatsInHouse INT 
) 

INSERT INTO PopulationDetails 
VALUES('United States','California', 38332521, 53), 
('United States','Texas', 26448193, 36), 
('United States','New York', 19651127, 27), 
('United States','Florida', 19552860, 27), 
('United States','Illinois', 12882135, 18) 

我想我的输出应该看起来像下面。州的数量不是固定的,这些可能会根据要求而有所不同。

        United States    
       California  Texas  New York Florida  Illinois 
Population  38332521  26448193 19651127 19552860 12882135 
SeatsInHouse 53    36   27   27   18 
+2

你不可能真的有像SQL那样的多级结果。您必须在您的应用程序或甚至SSRS等表示层中执行此操作。你可以做的最多的就是让列名的前面的国家类似于“UnitedStates_California”等 – Taryn 2014-09-23 10:58:38

回答

3

正如我在我的评论中所说的,多级列标题不能通过SQL来完成。您必须在应用程序或SSRS等表示层中格式化数据。如果您想要将countrystate值“合在一起”,那么您必须将这些名称拼接在一起,并创建新的列名称。

如果你想要得到的结果在SQL,我会通过连接countrystate,并且unpivot列​​和SeatsInHouse首先启动。此过程的基本语法为:

select 
    country_state = replace(pd.Country +'_'+pd.State, ' ', ''), 
    c.col, 
    c.value 
from dbo.PopulationDetails pd 
cross apply 
(
    values 
     ('Population', pd.population), 
     ('SeatsInHouse', pd.SeatsInHouse) 
) c (col, value); 

请参阅SQL Fiddle with Demo。这给出了一个结果:

|   COUNTRY_STATE |   COL | VALUE | 
|-------------------------|--------------|----------| 
| UnitedStates_California | Population | 38332521 | 
| UnitedStates_California | SeatsInHouse |  53 | 
|  UnitedStates_Texas | Population | 26448193 | 
|  UnitedStates_Texas | SeatsInHouse |  36 | 
| UnitedStates_NewYork | Population | 19651127 | 
| UnitedStates_NewYork | SeatsInHouse |  27 | 

你会看到,你现在有两行对每个Country_State组合。现在,您可以透视这些Country_State值代入列:

select col, UnitedStates_California, UnitedStates_Texas, 
    UnitedStates_NewYork, UnitedStates_Florida, 
    UnitedStates_Illinois 
from 
(
    select 
     country_state = replace(pd.Country +'_'+pd.State, ' ', ''), 
     c.col, 
     c.value 
    from dbo.PopulationDetails pd 
    cross apply 
    (
     values 
      ('Population', pd.population), 
      ('SeatsInHouse', pd.SeatsInHouse) 
    ) c (col, value) 
) d 
pivot 
(
    max(value) 
    for country_state in (UnitedStates_California, UnitedStates_Texas, 
          UnitedStates_NewYork, UnitedStates_Florida, 
          UnitedStates_Illinois) 
) piv; 

SQL Fiddle with Demo

现在,如果您需要动态完成此操作,那么您必须使用动态SQL来创建随后执行的字符串。

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

select @cols = STUFF((SELECT ',' + QUOTENAME(country_state) 
        from 
        (
         select country_state = replace(Country +'_'+State, ' ', '') 
         from dbo.PopulationDetails 
        ) d 
        group by country_state 
        order by country_state 
      FOR XML PATH(''), TYPE 
      ).value('.', 'NVARCHAR(MAX)') 
     ,1,1,'') 

set @query = 'SELECT col, ' + @cols + ' 
      from 
      (
       select 
        country_state = replace(pd.Country +''_''+pd.State, '' '', ''''), 
        c.col, 
        c.value 
       from dbo.PopulationDetails pd 
       cross apply 
       (
        values 
         (''Population'', pd.population), 
         (''SeatsInHouse'', pd.SeatsInHouse) 
       ) c (col, value) 
      ) x 
      pivot 
      (
       max(value) 
       for country_state in (' + @cols + ') 
      ) p ' 

exec sp_executesql @query; 

参见SQL Fiddle with Demo。两者都给出了结果:

|   COL | UNITEDSTATES_CALIFORNIA | UNITEDSTATES_FLORIDA | UNITEDSTATES_ILLINOIS | UNITEDSTATES_NEWYORK | UNITEDSTATES_TEXAS | 
|--------------|-------------------------|----------------------|-----------------------|----------------------|--------------------| 
| Population |    38332521 |    19552860 |    12882135 |    19651127 |   26448193 | 
| SeatsInHouse |      53 |     27 |     18 |     27 |     36 |