web-dev-qa-db-fra.com

Comment faire pivoter des lignes dans des colonnes (pivot personnalisé)

J'ai une table de base de données SQL semblable au suivant:

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

Je voudrais qu'il soit affiché comme suit: type de tableau croisé ou pivot 

Day   P1   P2   P3   P4   P5   P6   P7

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

Quel serait le moyen idéal de le faire? Quelqu'un peut-il s'il vous plaît me montrer le code SQL s'il vous plaît?

24
Babu

Vous pourriez probablement le faire avec la fonction PIVOT, mais je préfère la méthode old school:

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
  • J'ai changé certains noms de colonnes pour éviter les mots réservés
18
Tom H

Juste au cas où vous voulez la nouvelle méthode scolaire. (L'instruction de tableau croisé dynamique doit fonctionner dans SQL2005 +, le bit VALUES pour les données d'exemple uniquement 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; 

Résultat

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

Tu pourrais essayer...

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;

mais je ne peux pas dire que je l'aime beaucoup. Mieux que rien, cependant.

1
Brian Hooper

Utilisez cross apply pour obtenir toutes les valeurs dans un format délimité par des virgules dans une seule colonne. au lieu de "7" colonnes différentes. La requête suivante peut être utilisée pour tout mappage de colonne-> ligne

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)

Vous obtiendrez [Ch, Ph, Mth, CS2, Lab1, Lab2, Lab3] dans une colonne pour Mon et ainsi de suite ... Vous pouvez l'utiliser comme une table pour interroger un jour particulier.

J'espère que cela t'aides

1
Baaju
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]
1
Flipping
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;
0
mr_eclair