2010-09-15 9 views
8

tengo datosCómo diseño de la consulta para la creación de columnas dinámicas de las filas

Tabla 1

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

Tabla 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 

Quiero devolver datos en formato siguiente:

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 

Basado en el máximo no de columnas para ID Quiero crear nombres de columnas y luego convertir filas en columnas. ¿Es posible hacerlo usando una consulta SQL?

+0

¡Utilice el Generador de informes para generar informes! –

+0

¿Hay alguna razón por la cual tendría dos columnas por año en lugar de tener el año el nombre de la columna? de esa forma todos tus años están agrupados. – DForck42

Respuesta

1

Esta consulta debería ayudar

;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í pero no estoy seguro de cuántos años estarán allí, mis columnas pueden extenderse más allá de año4 como yr5, yr6, yr7 –

+0

A diferencia de las filas, debe tener un número definido de columnas en la cláusula SELECT (no mencionaré SQL dinámico aquí).Puede agregar más columnas a esta consulta, que produciría todos los valores NULL cuando los años no existan. – bobs

5

He creado una tabla llamada "Tabla 2", que contiene los datos que ha mostrado anteriormente en el encabezado de la tabla 2.

Aquí es el SQL que utilicé en 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 

Lo anterior SQL dará lugar a esto:

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 razón por la que no se ve NULL valores se debe a la ELSE en cada declaración CASE. Si prefiere tener NULL valores, simplemente elimine ELSE 0 y ELSE '' según sea necesario.

No sé en este momento si es posible hacer esto genérico, por ejemplo: procesar una cantidad desconocida de FID distintos, ya que esto también significaría generar los nombres de las columnas (Yr1, al1, Yr2, etc.) genéricamente.

Podría lograr esto con SQL dinámico, pero como no soy un gran admirador del SQL dinámico, trataría de buscar otra forma de solucionarlo.

- Editar (enfoque de pivote Agregado de completitud) -

Miré el enlace de Joe Stefanelli publicada y añade el SQL a continuación para su requisito. Aunque no me gusta la idea del SQL dinámico, no pude encontrar otra forma en esta instancia específica.

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) 

Esto dará lugar a la siguientes aparatos:

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 

función y el formato de acercarse más le gusta, por lo menos tienes las opciones de línea para out.

+0

No he visto bobs responder mientras estaba trabajando en el mío. Lo mismo básicamente. No fue para duplicar la respuesta. – Nope

Cuestiones relacionadas