2014-09-23 94 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 |