如何将行旋转到列(自定义旋转)
Posted
技术标签:
【中文标题】如何将行旋转到列(自定义旋转)【英文标题】:How to pivot rows into columns (custom pivoting) 【发布时间】:2011-03-08 10:37:46 【问题描述】:我有一个类似下面的 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代码吗?
【问题讨论】:
【参考方案1】:你可以用 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
我更改了一些列名以避免保留字
【讨论】:
+1:你速度更快,并且有 ORDER BY。所以我要补充一点:如您所见,动态列将需要使用动态 SQL。有 ANSI PIVOT 语法,但仅在 SQL Server 2005+ 和 Oracle 11g 上受支持。 我目前正在 SQLite 中执行此操作,但它似乎是一项相当密集的操作。有谁知道是否有更高效的解决方案? 我不相信 SQLite 有任何内置的数据透视函数,所以这可能就是你所坚持的。虽然我不使用 SQLite,所以也许对特定 SQL 供应商有更多经验的人会有更好的主意。【参考方案2】:以防万一您确实想要新的学校方法。 (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
【讨论】:
为什么选择 Max(主题)?这是因为 PIVOT 必须采用聚合函数吗? @JBRWilkinson 是的。确切地。日/期间组合应该只有一个匹配记录,因此“MIN”同样有效。【参考方案3】:你可以试试……
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;
但我不能说我非常喜欢它。不过,总比没有好。
【讨论】:
【参考方案4】:使用交叉应用以逗号分隔格式在单个列中获取所有值。而不是“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 的一列中获得 [Ch,Ph,Mth,CS2,Lab1,Lab2,Lab3] 等...您可以将其用作查询任何特定日期的表格。
希望对你有帮助
【讨论】:
【参考方案5】: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]
【讨论】:
【参考方案6】: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;
【讨论】:
以上是关于如何将行旋转到列(自定义旋转)的主要内容,如果未能解决你的问题,请参考以下文章
如何在自定义 UICollectionView 的旋转后触发 drawrect?