2010-06-25 145 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