2010-09-15 74 views
8

我有數據如何設計查詢從行創建動態列

表1

ID  Name 
----------- 
1  n1 
2  n2 
3  n4 

表2

FID YearS Val 
---------------------- 
1  2008  Up 
1  2009  Down 
1  2010  Up 
2  2000  Up 
2  2001  Down 
2  2002  Up 
2  2003  Up 
3  2009  Down 
3  2010  Up 

我想返回下列格式的數據:

ID Yr1 Val1 Yr2 Val2 Yr3 Val3 Yr4 Val4 
-------------------------------------------------------- 
1 2008 Up  2009 Down 2010 Up  NULL Null 
2 2000 Up  2001 Down 2002 Up  2003 Up 
3 2009 Down 2010 Up NULL NULL NULL Null 

根據最大值沒有列的ID我想創建列名稱,然後轉換列中的行。這可能使用SQL查詢嗎?

+0

使用Report Builder構建報告! – 2010-09-15 18:53:53

+0

是否有理由爲什麼每年會有兩列,而不是年份列的名稱?這樣你所有的年份都被分組了。 – DForck42 2010-09-15 19:24:37

回答

1

這個查詢應該幫助

;WITH cte AS 
    (
    SELECT *, ROW_NUMBER() OVER (PARTITION BY FID ORDER BY FID, YearS) AS NUMBER 
    FROM Table2 
    ) 

SELECT t.ID, MAX(CASE WHEN cte.number = 1 THEN cte.YearS END) as yr1, MAX(CASE WHEN cte.number = 1 THEN cte.Val END) as val1, 
MAX(CASE WHEN cte.number = 2 THEN cte.YearS END) as yr2, MAX(CASE WHEN cte.number = 2 THEN cte.Val END) as val2, 
MAX(CASE WHEN cte.number = 3 THEN cte.YearS END) as yr3, MAX(CASE WHEN cte.number = 3 THEN cte.Val END) as val3, 
MAX(CASE WHEN cte.number = 4 THEN cte.YearS END) as yr4, MAX(CASE WHEN cte.number = 4 THEN cte.Val END) as val4 
FROM Table1 T 
JOIN cte ON t.ID = cte.FID 
GROUP BY t.ID 
+0

是的,但我不知道會有多少年,我的列可以延伸到yr4之外,比如yr5,yr6,yr7 – 2010-09-15 19:19:53

+0

與行不同,您必須在SELECT子句中具有已定義數量的列(我不會提及動態SQL在這裏)。您可以向此查詢添加更多列,當這些年份不存在時,這些列將生成所有NULL值。 – bobs 2010-09-15 19:47:31

5

我創建了一個名爲「表2」中,則包含您已在表2標題下上面顯示的數據。

下面是我在SQL Server 2008中使用

WITH RankedValues AS 
(
    SELECT 
     FID AS ID, 
     YearS, 
     ROW_NUMBER() OVER(PARTITION BY FID ORDER BY YearS) AS YearSRank, 
     Val 
    FROM 
     Table2 
) 
SELECT 
    ID, 
    MAX((CASE WHEN YearSRank = 1 THEN YearS ELSE 0 END)) AS Yr1, 
    MAX((CASE WHEN YearSRank = 1 THEN Val ELSE '' END)) AS Val1, 
    MAX((CASE WHEN YearSRank = 2 THEN YearS ELSE 0 END)) AS Yr2, 
    MAX((CASE WHEN YearSRank = 2 THEN Val ELSE '' END)) AS Val2, 
    MAX((CASE WHEN YearSRank = 3 THEN YearS ELSE 0 END)) AS Yr3, 
    MAX((CASE WHEN YearSRank = 3 THEN Val ELSE '' END)) AS Val3, 
    MAX((CASE WHEN YearSRank = 4 THEN YearS ELSE 0 END)) AS Yr4, 
    MAX((CASE WHEN YearSRank = 4 THEN Val ELSE '' END)) AS Val4 
FROM 
    RankedValues 
GROUP BY 
    ID 

上面的SQL將導致這個SQL:

ID Yr1  Val1 Yr2  Val2 Yr3  Val3 Yr4  Val4 
--------------------------------------------------------------------- 
1 2008 Up 2009 Down 2010 Up 0  
2 2000 Up 2001 Down 2002 Up 2003 Up 
3 2009 Down 2010 Up  0    0  

看不到NULL值的原因是因爲ELSE的在每個CASE聲明中。 如果您寧願有NULL值,只需根據需要刪除ELSE 0ELSE ''

我不知道在這個時候,如果有可能使這個通用的,比如:過程不同的FID未知量,因爲這也意味着產生的列名(YR1,AL1,YR2,等等。)一般。

你可以用動態SQL來實現這個目標,但由於我不是動態SQL的忠實粉絲,所以我會試着去研究處理這個問題的另一種方法。

- Edit(對於completness加樞方法) -

我看着鏈接喬·斯特凡內利公佈和我說下面的SQL爲您的要求。雖然我不喜歡動態SQL的思想,但在這個特定的實例中我找不到任何其他方法。

DECLARE @query VARCHAR(4000) 
DECLARE @years VARCHAR(2000) 

SELECT @years = STUFF((
    SELECT DISTINCT 
     '],[' + ltrim(str(YearS)) 
    FROM Table2 
    ORDER BY '],[' + ltrim(str(YearS)) 
    FOR XML PATH('')), 1, 2, '') + ']' 

SET @query = 
    'SELECT * FROM 
    (
     SELECT FID AS ID,YearS,Val 
     FROM Table2 
    ) AS t 
    PIVOT (MAX(Val) FOR YearS IN (' + @years + ')) AS pvt' 

EXECUTE (@query) 

這將導致follwing:

ID 2000 2001 2002 2003 2008 2009 2010 
--------------------------------------------------------- 
1 NULL NULL NULL NULL Up  Down Up 
2 Up  Down Up  Up  NULL NULL NULL 
3 NULL NULL NULL NULL NULL Down Up 

根據其格式和方法,你最喜歡的,至少你有你林立了。

+0

我在做我的工作時,我還沒有見過鮑勃的回答。基本一樣的東西。並不是要重複答案。 – Nope 2010-09-15 20:27:24