2010-06-25 16 views
24

Tengo una tabla de base de datos SQL similar al siguiente:Cómo pivotar filas en columnas (pivotantes medida)

Day Period Subject 

Mon 1   Ch 
Mon 2   Ph 
Mon 3   Mth 
Mon 4   CS 
Mon 5   Lab1 
Mon 6   Lab2 
Mon 7   Lab3 
Tue 1   Ph 
Tue 2   Ele 
Tue 3   Hu 
Tue 4   Ph 
Tue 5   En 
Tue 6   CS2 
Tue 7   Mth 

me gustaría que aparece de la siguiente manera: Tipo de tabla de referencias cruzadas o de pivote

Day P1 P2 P3 P4 P5 P6 P7 

Mon Ch Ph Mth CS2 Lab1 Lab2 Lab3 
Tue Ph Ele Hu Ph En CS2 Mth 

¿Cuál sería la forma ideal de hacerlo? ¿Puede alguien mostrarme el código Sql por favor?

Respuesta

17

Probablemente podría hacerlo con la función de pivote, pero yo prefiero el viejo método de la escuela:

SELECT 
    dy, 
    MAX(CASE WHEN period = 1 THEN subj ELSE NULL END) AS P1, 
    MAX(CASE WHEN period = 2 THEN subj ELSE NULL END) AS P2, 
    MAX(CASE WHEN period = 3 THEN subj ELSE NULL END) AS P3, 
    MAX(CASE WHEN period = 4 THEN subj ELSE NULL END) AS P4, 
    MAX(CASE WHEN period = 5 THEN subj ELSE NULL END) AS P5, 
    MAX(CASE WHEN period = 6 THEN subj ELSE NULL END) AS P6, 
    MAX(CASE WHEN period = 7 THEN subj ELSE NULL END) AS P7 
FROM 
    Classes 
GROUP BY 
    dy 
ORDER BY 
    CASE dy 
     WHEN 'Mon' THEN 1 
     WHEN 'Tue' THEN 2 
     WHEN 'Wed' THEN 3 
     WHEN 'Thu' THEN 4 
     WHEN 'Fri' THEN 5 
     WHEN 'Sat' THEN 6 
     WHEN 'Sun' THEN 7 
     ELSE 8 
    END 
  • he cambiado algunos nombres de columna para evitar palabras reservadas
+0

+1: Usted fue más rápido y tener el ORDER BY . Así que solo agregaré: como puede ver, las columnas dinámicas requerirán el uso de SQL dinámico. Existe la sintaxis ANSI PIVOT, pero solo es compatible con SQL Server 2005+ y Oracle 11g. –

+0

Actualmente estoy haciendo esto en SQLite, pero parece ser una operación bastante intensiva. ¿Alguien sabe si hay una solución más eficiente? – EnemyBagJones

+0

No creo que SQLite tenga ningún tipo de función de pivote integrada, por lo que es probable que esto sea lo que le impida. Aunque no uso SQLite, tal vez alguien con más experiencia con ese proveedor de SQL específico tenga una mejor idea. –

1

Usted podría intentar ...

SELECT DISTINCT Day, 
     (SELECT Subject 
      FROM my_table mt2 
      WHERE mt2.Day = mt.Day AND 
        Period = 1) AS P1, 
     (SELECT Subject 
      FROM my_table mt2 
      WHERE mt2.Day = mt.Day AND 
        Period = 2) AS P2, 
    . 
    . 
    etc 
    . 
    . 
    . 
    (SELECT Subject 
     FROM my_table mt2 
     WHERE mt2.Day = mt.Day AND 
       Period = 7) AS P7 
FROM my_table mt; 

pero no puedo decir que me gusta mucho. Mejor que nada, sin embargo.

1

Uso cruz se aplican a obtener todos los valores en un formato delimitado por comas en una sola columna. en lugar de "7" columnas diferentes. La siguiente consulta se puede utilizar para cualquier asignación columna-> fila

SELECT DISTINCT Day, [DerivedColumn] FROM <Table> A CROSS APPLY (SELECT Period + ',' FROM <Table> B WHERE A.Day = B.Day Order By Period FOR XML PATH('')) AS C (DerivedColumn) 

Usted recibirá [Ch, Ph, Mes, CS2, Lab1, Lab2, LAB3] en una columna de Mon y así sucesivamente ... Usted podría usar esto como una tabla para consultar cualquier día en particular.

Esperanza esto ayuda

12

Sólo en caso que usted desea que el nuevo método de la escuela. (La declaración de pivote debe trabajar en SQL2005 +, el bit VALUES para el ejemplo de datos sólo SQL2008)

WITH ExampleData AS 
(
SELECT X.* 
    FROM (VALUES 
('Mon', 1, 'Ch'), 
('Mon', 2, 'Ph'), 
('Mon', 3, 'Mth'), 
('Mon', 4, 'CS'), 
('Mon', 5, 'Lab1'), 
('Mon', 6, 'Lab2'), 
('Mon', 7, 'Lab3'), 
('Tue', 1, 'Ph'), 
('Tue', 2, 'Ele'), 
('Tue', 3, 'Hu'), 
('Tue', 4, 'Ph'), 
('Tue', 5, 'En'), 
('Tue', 6, 'CS2'), 
('Tue', 7, 'Mth') 
) AS X (Day, Period, Subject) 
) 

SELECT Day, [1] AS P1, [2] AS P2,[3] AS P3, [4] AS P4, [5] AS P5,[6] AS P6,[7] AS P7 
FROM ExampleData 
PIVOT 
( 
Max(Subject) 
FOR Period IN ([1], [2],[3],[4], [5],[6], [7]) 
) AS PivotTable; 

Resultado

Day P1 P2 P3 P4 P5 P6 P7 
---- ---- ---- ---- ---- ---- ---- ---- 
Mon Ch Ph Mth CS Lab1 Lab2 Lab3 
Tue Ph Ele Hu Ph En CS2 Mth 
+1

¿Por qué Max (Asunto)? ¿Esto es porque PIVOT tiene que tomar una función agregada? – JBRWilkinson

+1

@JBRWilkinson Sí. Exactamente. Solo debería haber un registro coincidente para una combinación Día/Período, por lo que 'MIN' hubiera funcionado igual de bien. –

0
with pivot_data as 
(
select [day], -- groping column 
period, -- spreading column 
subject -- aggreate column 
from pivot_tb 
) 
select [day], [1] AS P1, [2] AS P2,[3] AS P3, [4] AS P4, [5] AS P5,[6] AS P6,[7] AS P7 
from pivot_data 
pivot (max(subject) for period in ([1], [2],[3],[4], [5],[6], [7])) as p; 
1
DECLARE @TIMETABLE TABLE (
    [Day]  CHAR(3), 
    [Period] TINYINT, 
    [Subject] CHAR(5) 
) 
INSERT INTO @TIMETABLE([Day], [Period], [Subject]) 
VALUES 
    ('Mon', 1, 'Ch'), 
    ('Mon', 2, 'Ph'), 
    ('Mon', 3, 'Mth'), 
    ('Mon', 4, 'CS'), 
    ('Mon', 5, 'Lab1'), 
    ('Mon', 6, 'Lab2'), 
    ('Mon', 7, 'Lab3'), 
    ('Tue', 1, 'Ph'), 
    ('Tue', 2, 'Ele'), 
    ('Tue', 3, 'Hu'), 
    ('Tue', 4, 'Ph'), 
    ('Tue', 5, 'En'), 
    ('Tue', 6, 'CS2'), 
    ('Tue', 7, 'Mth') 

SELECT 
    [Day], 
    MAX(CASE [Period] WHEN 1 THEN [Subject] END) AS P1, 
    MAX(CASE [Period] WHEN 2 THEN [Subject] END) AS P2, 
    MAX(CASE [Period] WHEN 3 THEN [Subject] END) AS P3, 
    MAX(CASE [Period] WHEN 4 THEN [Subject] END) AS P4, 
    MAX(CASE [Period] WHEN 5 THEN [Subject] END) AS P5, 
    MAX(CASE [Period] WHEN 6 THEN [Subject] END) AS P6, 
    MAX(CASE [Period] WHEN 7 THEN [Subject] END) AS P7 
FROM @TIMETABLE 
GROUP BY [Day] 
+0

¿Es ese SQL ANSI? – ViniciusPires