web-dev-qa-db-ja.com

行を列にピボットする方法(カスタムピボット)

次のようなSQLデータベーステーブルがあります。

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

次のように表示したい:クロス集計またはピボットの種類

Day   P1   P2   P3   P4   P5   P6   P7

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

それを行うための理想的な方法は何でしょうか?誰かが私にSQLコードを見せてくださいませんか?

25
Babu

おそらくPIVOT機能でそれを行うことができますが、私は古い学校の方法が好きです:

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
  • 予約語を避けるためにいくつかの列名を変更しました
19
Tom H

新しい学校の方法が必要な場合に備えてください。 (PivotステートメントはSQL2005 +で機能するはずです。サンプルデータのみの場合はVALUESビットのみ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; 

結果

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

試すことができます...

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;

でも私はそれがとても好きだとは言えませんしかし、何もないよりはましだ.

1
Brian Hooper

クロスアプライを使用して、単一の列にコンマ区切り形式のすべての値を取得します。 「7」の異なる列の代わりに。次のクエリは、任意の列->行マッピングに使用できます

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)

Monなどの1つの列に[Ch、Ph、Mth、CS2、Lab1、Lab2、Lab3]が表示されます。これを特定の日を照会するテーブルとして使用できます。

お役に立てれば

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