2010-06-25 40 views
24

我有類似如下的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代碼嗎?

回答

17

你也許可以用旋轉功能做到這一點,但我更喜歡老派的方法:

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 
  • 我改變了一些列的名稱,以避免保留字
+0

+1:你是快和有ORDER BY 。所以我只是補充一下:正如你所看到的,動態列需要使用動態SQL。有ANSI PIVOT語法,但它僅在SQL Server 2005+和Oracle 11g上受支持。 – 2010-06-25 19:42:28

+0

我目前在SQLite中這樣做,但它似乎是一個相當密集的操作。有誰知道是否有更高性能的解決方案? – EnemyBagJones 2018-01-30 20:27:27

+0

我不相信SQLite有任何內置的透視功能,所以這可能是你堅持。儘管我不使用SQLite,但也許有人對這個特定的SQL供應商有更多的經驗有更好的主意。 – 2018-01-30 21:21:55

1

你可以試試...

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

使用交叉適用於在單個列中以逗號分隔格式獲取所有值。而不是「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) 

你會得到〔CH,PH,第M,CS2,實驗室1,實驗2,Lab3的在一列星期一等等......你可以用它作爲查詢任何特定日子的表格。

希望這有助於

12

只是櫃面你想新學校的方法。 (該樞軸語句應在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 
+1

爲什麼最大(主題)?這是因爲PIVOT必須採用聚合函數嗎? – JBRWilkinson 2010-07-06 11:41:29

+1

@JBRWilkinson是的。究竟。對於日期/期間組合應該只有一個匹配記錄,所以'MIN'的效果一樣好。 – 2010-07-06 12:02:15

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

是SQL ANSI嗎? – ViniciusPires 2015-04-16 18:49:23