2010-11-01 306 views
3

如何動態創建列我有3個表。 Team,Option,OptionTeam。
團隊擁有TeamId和名稱
期權持有OptionId,選項組
OptionTeam持有TeamId,OptionId,選項組在SQL SELECT語句

select a.TeamId, a.Name 
(select count(*) from OptionTeam ot where ot.TeamId=a.TeamId and ot.OptionGroup=4) as Option1, 
(select count(*) from OptionTeam ot where ot.TeamId=a.TeamId and ot.OptionGroup=5) as Option2, 
(select count(*) from OptionTeam ot where ot.TeamId=a.TeamId and ot.OptionGroup=6) as Option3, 
(select count(*) from OptionTeam ot where ot.TeamId=a.TeamId and ot.OptionGroup=11) as Option4 
from Team a 

我想球隊的名單,以及額外的列表示每個多少選項小組連接到每個小組。這是由上面的查詢完成,但我想從表中選擇選項組的值替換4,5,6,11。
它必須是動態的,因爲未來可能會有一個新的OptionGroup,我希望存儲過程能夠處理它。

的樣本數據:

Team 
TeamId 
1 
2 
3 

選項

OptionId | OptionGroup 
11 | 4 
12 | 5 
13 | 4 
14 | 4 
15 | 5 

OptionTeam

TeamId | OptionId | OptionGroup 
1 | 11 | 4 
1 | 13 | 4 
2 | 12 | 5 
2 | 14 | 4 
3 | 15 | 5 

這個名單我想是

TeamId | Group4 (OptionGroup=4) | Group5 (OptionGroup=5) 
1 | 2 | 0 
2 | 1 | 1 
3 | 0 | 1 
+1

您正在使用什麼RDBMS? MySQL,SQL Server等? – JNK 2010-11-01 14:15:56

+0

@JNK SQL服務器 – Stavros 2010-11-01 14:36:05

回答

4

你需要一個動態的支點來做到這一點。這裏的存儲過程:

CREATE PROC [dbo].[pivotsp] 
     @query AS NVARCHAR(MAX),     -- The query, can also be the name of a table/view. 
     @on_rows AS NVARCHAR(MAX),     -- The columns that will be regular rows. 
     @on_cols AS NVARCHAR(MAX),     -- The columns that are to be pivoted. 
     @agg_func AS NVARCHAR(257) = N'SUM',   -- Aggregate function. 
     @agg_col AS NVARCHAR(MAX),     -- Column to aggregate. 
     @output AS NVARCHAR(257) = N'',    -- Table for results 
     @debug AS bit = 0       -- 1 for debugging 
    AS 

    -- Example usage: 
    -- exec pivotsp 
    --   'select * from vsaleshistory', 
    --   'market,marketid,family,familyid,Forecaster,Forecasterid,product,productid', 
    --   'month', 
    --   'sum', 
    --   'ku', 
    --   '##sales' 

    -- Input validation 
    IF @query IS NULL OR @on_rows IS NULL OR @on_cols IS NULL 
     OR @agg_func IS NULL OR @agg_col IS NULL 
    BEGIN 
     RAISERROR('Invalid input parameters.', 16, 1); 
     RETURN; 
    END 

    -- Additional input validation goes here (SQL Injection attempts, etc.) 

    BEGIN TRY 
     DECLARE 
     @sql  AS NVARCHAR(MAX), 
     @cols AS NVARCHAR(MAX), 
     @newline AS NVARCHAR(2); 

     SET @newline = NCHAR(13) + NCHAR(10); 

     -- If input is a valid table or view 
     -- construct a SELECT statement against it 
     IF COALESCE(OBJECT_ID(@query, N'U'), 
        OBJECT_ID(@query, N'V')) IS NOT NULL 
     SET @query = N'SELECT * FROM ' + @query; 

     -- Make the query a derived table 
     SET @query = N'(' + @query + N') AS Query'; 

     -- Handle * input in @agg_col 
     IF @agg_col = N'*' 
     SET @agg_col = N'1'; 

     -- Construct column list 
     SET @sql = 
      N'SET @result = '         + @newline + 
      N' STUFF('           + @newline + 
      N' (SELECT N'','' + quotename(' 
         + 'CAST(pivot_col AS sysname)' + 
         + ') AS [text()]'       + @newline + 
      N'  FROM (SELECT DISTINCT(' 
         + @on_cols + N') AS pivot_col'    + @newline + 
      N'   FROM' + @query + N') AS DistinctCols' + @newline + 
      N'  ORDER BY pivot_col'       + @newline + 
      N'  FOR XML PATH(''''))'       + @newline + 
      N' ,1, 1, N'''');' 

     IF @debug = 1 
     PRINT @sql 

     EXEC sp_executesql 
     @stmt = @sql, 
     @params = N'@result AS NVARCHAR(MAX) OUTPUT', 
     @result = @cols OUTPUT; 

     IF @debug = 1 
     PRINT @cols 

     -- Create the PIVOT query 
     IF @output = N'' 
      begin 
      SET @sql = 
       N'SELECT *'           + @newline + 
       N'FROM (SELECT ' 
           + @on_rows 
           + N', ' + @on_cols + N' AS pivot_col' 
           + N', ' + @agg_col + N' AS agg_col'  + @newline + 
       N'  FROM ' + @query + N')' + 
           + N' AS PivotInput'      + @newline + 
       N' PIVOT(' + @agg_func + N'(agg_col)'    + @newline + 
       N' FOR pivot_col IN(' + @cols + N')) AS PivotOutput;' 
      end 
     ELSE 
      begin 
      set @sql = 'IF EXISTS (SELECT * FROM tempdb.sys.objects WHERE ' + 
       'name = ''' + @output + ''' AND type = N''U'') DROP TABLE tempdb.' + @output 
      EXEC sp_executesql @sql; 

      SET @sql = 
       N'SELECT * INTO ' + @output       + @newline + 
       N'FROM (SELECT ' 
           + @on_rows 
           + N', ' + @on_cols + N' AS pivot_col' 
           + N', ' + @agg_col + N' AS agg_col'  + @newline + 
       N'  FROM ' + @query + N')' + 
           + N' AS PivotInput'      + @newline + 
       N' PIVOT(' + @agg_func + N'(agg_col)'    + @newline + 
       N' FOR pivot_col IN(' + @cols + N')) AS PivotOutput;' 
      end 

     IF @debug = 1 
      PRINT @sql 

     EXEC sp_executesql @sql; 
    END TRY 
    BEGIN CATCH 
     DECLARE 
     @error_message AS NVARCHAR(2047), 
     @error_severity AS INT, 
     @error_state AS INT; 

     SET @error_message = ERROR_MESSAGE(); 
     SET @error_severity = ERROR_SEVERITY(); 
     SET @error_state = ERROR_STATE(); 

     RAISERROR(@error_message, @error_severity, @error_state); 

     RETURN; 
    END CATCH 

就這樣,很容易在轉動列的可變數目:

EXEC pivotsp 
     'SELECT TeamID, OptionGroup, OptionID AS Options FROM OptionTeam', 
     'Teamid',  -- Row headers 
     'optiongroup', -- item to aggregate 
     'count',   -- aggregation function 
     'optiongroup', -- Column header 
     '##temp'   -- output table name 
    SELECT * FROM ##temp 

結果:

Teamid 4 5 
    1 2 0 
    2 1 1 
    3 0 1 
2
SELECT a.*, o.optionGroup, COUNT(*) 
FROM team a 
CROSS JOIN 
     option o 
JOIN OptionTeam ot 
ON  ot.teamId = a.teamId 
     AND ot.optionGroup = o.optionGroup 
WHERE o.OptionId = @id 
GROUP BY 
     a.teamId, o.optionGroup 
+0

你在哪裏得到@id? – Stavros 2010-11-01 14:39:17

+0

@Stavros:這就是我要問你什麼:)請發表您的表的樣本數據,你想要得到的輸出。 – Quassnoi 2010-11-01 14:42:22

+0

@Quassnoi:我剛剛添加了示例數據:) – Stavros 2010-11-01 15:19:04

0
select teamID, 
sum(case when optionGroup = 4 then 1 else 0 end) as optionGroup4, 
sum(case when optionGroup = 5 then 1 else 0 end) as optionGroup5, 
from optionteam 
group by teamID 

添加更多optiongroups而無需修改代碼,試圖通過那場分組:

select teamID,optionGroup,count(optionID) as optionCount 
from optionteam 
group by teamID,optionGroup 
+0

這不會產生不同的列:( – Stavros 2010-11-02 09:38:53

+0

正確的,你必須轉動的結果 – Beth 2010-11-02 15:24:47