2010-09-15 10 views
8

Ho datiCome progettare query per la creazione di colonne dinamiche da file

Table1

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

Table2

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 

voglio restituire i dati in formato seguente:

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 

Basato sul numero massimo no di colonne per ID voglio creare nomi di colonne e quindi convertire righe in colonne. È possibile farlo usando una query sql?

+0

Utilizzare Report Builder per creare report! –

+0

c'è un motivo per cui avresti due colonne all'anno invece di avere l'anno il nome della colonna? in questo modo tutti i tuoi anni sono raggruppati. – DForck42

risposta

1

Questa query dovrebbe aiutare

;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

sì ma non sono sicuro di quanti anni ci saranno, le mie colonne possono estendersi oltre yr4 come yr5, yr6, yr7 –

+0

A differenza delle righe, devi avere un numero definito di colonne nella clausola SELECT (non farò menzione SQL dinamico qui).È possibile aggiungere più colonne a questa query, che produrrebbe tutti i valori NULL quando gli anni non esistono. – bobs

5

ho creato una tabella chiamata "Table2", contenente i dati che avete mostrato in precedenza sotto la rubrica Tabella 2.

Ecco l'SQL che ho usato in 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 

È possibile che SQL si tradurrà in questo:

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  

La ragione per cui non si vede NULL valori è a causa del ELSE in ciascuna istruzione CASE. Se si preferiscono valori NULL, rimuovere semplicemente ELSE 0 e ELSE '' come richiesto.

Al momento non so se è possibile rendere questo generico, ad esempio: elaborare una quantità sconosciuta di FID distinti, poiché ciò significherebbe anche generare i nomi delle colonne (Yr1, al1, Yr2, ecc.) genericamente.

È possibile raggiungere questo obiettivo con SQL dinamico ma, poiché non sono un grande fan dell'SQL dinamico, proverei a cercare un altro modo di gestirlo.

- Modifica (Added approccio perno per completezza) -

Ho guardato il link Joe Stefanelli postato e ho aggiunto lo SQL di seguito per il vostro requisito. Anche se non mi piace l'idea di SQL dinamico non sono riuscito a trovare nessun altro modo in questa specifica istanza.

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) 

Ciò comporterà il 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 

A seconda che formato e avvicinarsi a voi piace di più, almeno hai le opzioni in fila fuori.

+0

Non ho visto la risposta di Bob mentre stavo lavorando al mio. La stessa cosa fondamentalmente. Non intendevo duplicare la risposta. – Nope

Problemi correlati