转置即旋转数据表的横纵方向,常用来改变数据布局,以便用新的角度观察,下面主要给大家介绍关于SQL行列转置以及非常规行列转置.
在SQL查询中转换和转置数据(非数字)可以通过使用CASE语句和聚合函数来实现。
转换数据是指将行数据转换为列数据,可以使用CASE语句将不同的值转换为不同的列。
将行转置为列
下面我们将尝试如何获取格式化数据以进行分析,并对其进行透视以进行演示或绘制图表。
实例一
原数据集
我们想使其看起来像这样:
让我们首先聚合数据,以显示每个联盟中每年的玩家数量:
SELECT teams.conference AS conference,
players.year,
COUNT(1) AS players
FROM benn.college_football_players players
JOIN benn.college_football_teams teams
ON teams.school_name = players.school_name
GROUP BY 1,2
ORDER BY 1,2
为了转换数据,我们需要将上述查询放入子查询中。在开始进行转换之前,创建子查询并从中选择所有列可能会有所帮助。在查询未运行时,以此类增量步骤重新运行查询可以更轻松地进行调试。请注意,您可以从子查询中消除该子句,因为我们将对外部查询中的结果重新排序。
SELECT *
FROM (
SELECT teams.conference AS conference,
players.year,
COUNT(1) AS players
FROM benn.college_football_players players
JOIN benn.college_football_teams teams
ON teams.school_name = players.school_name
GROUP BY 1,2
) sub
假设按计划工作(结果看起来应该与第一个查询完全相同),那么是时候将结果分成不同年份的不同列了。语句中的每个项目都会创建一个列,因此您必须为每年创建一个单独的列:
SELECT conference,
SUM(CASE WHEN year = 'FR' THEN players ELSE NULL END) AS fr,
SUM(CASE WHEN year = 'SO' THEN players ELSE NULL END) AS so,
SUM(CASE WHEN year = 'JR' THEN players ELSE NULL END) AS jr,
SUM(CASE WHEN year = 'SR' THEN players ELSE NULL END) AS sr
FROM (
SELECT teams.conference AS conference,
players.year,
COUNT(1) AS players
FROM benn.college_football_players players
JOIN benn.college_football_teams teams
ON teams.school_name = players.school_name
GROUP BY 1,2
) sub
GROUP BY 1
ORDER BY 1
从技术上讲,您现在已经完成了目标。但仍然可以做得更好一点。您会注意到,上面的查询会生成一个按 Conference 的字母顺序排序的列表。添加一个 “total players” 列并按该列(从大到小)排序可能更有意义:
SELECT conference,
SUM(players) AS total_players,
SUM(CASE WHEN year = 'FR' THEN players ELSE NULL END) AS fr,
SUM(CASE WHEN year = 'SO' THEN players ELSE NULL END) AS so,
SUM(CASE WHEN year = 'JR' THEN players ELSE NULL END) AS jr,
SUM(CASE WHEN year = 'SR' THEN players ELSE NULL END) AS sr
FROM (
SELECT teams.conference AS conference,
players.year,
COUNT(1) AS players
FROM benn.college_football_players players
JOIN benn.college_football_teams teams
ON teams.school_name = players.school_name
GROUP BY 1,2
) sub
GROUP BY 1
ORDER BY 2 DESC
实例二
假设有一个表格包含学生的姓名和科目成绩:
姓名 科目 成绩
-----------------
张三 语文 80
张三 数学 90
李四 语文 85
李四 数学 95
如果要将科目转换为列,可以使用如下SQL查询:
SELECT
姓名,
MAX(CASE WHEN 科目 = '语文' THEN 成绩 END) AS 语文,
MAX(CASE WHEN 科目 = '数学' THEN 成绩 END) AS 数学
FROM
表格
GROUP BY
姓名;
转置数据是指将列数据转换为行数据,可以使用UNION ALL和CASE语句来实现。例如,假设有一个表格包含学生的姓名和语文、数学成绩:
姓名 语文 数学
-----------------
张三 80 90
李四 85 95
如果要将科目转换为行,可以使用如下SQL查询:
SELECT
姓名,
'语文' AS 科目,
语文 AS 成绩
FROM
表格
UNION ALL
SELECT
姓名,
'数学' AS 科目,
数学 AS 成绩
FROM
表格;
实际应用中,可以根据具体需求和数据结构选择适合的方法进行转换和转置。对于更复杂的数据转换和转置需求,可以结合使用子查询、临时表等技术来实现。
将列转置为行
您在 Internet 上找到的很多数据都是为了消费而非分析而格式化的。
实例一
如下表,显示了2000年到2012年,全球地震的数量
在这种格式中,回答诸如“地震的平均震级是多少”之类的问题是具有挑战性的。如果数据显示在 3 列中:“magnitude”、“year”和“number of earthquakes”,那就容易得多了。以下是将数据转换为该形式的方法:
注意:列名称以 'year_' 开头,因为要求列名称以字母开头。
这里要做的第一件事是创建一个表,将原始表中的所有列为新表中的行。除非你有大量的列要转换,否则最简单的方法通常是在子查询中列出它们:
SELECT year
FROM (VALUES (2000),(2001),(2002),(2003),(2004),(2005),(2006),
(2007),(2008),(2009),(2010),(2011),(2012)) v(year)
获得此项后,您可以将其与worldwide_earthquakes表交叉联接以创建扩展视图
SELECT years.*,
earthquakes.*
FROM tutorial.worldwide_earthquakes earthquakes
CROSS JOIN (
SELECT year
FROM (VALUES (2000),(2001),(2002),(2003),(2004),(2005),(2006),
(2007),(2008),(2009),(2010),(2011),(2012)) v(year)
) years
请注意,其中的每一行都会复制 13 次。最后要做的是使用一个语句来解决这个问题,该语句从表中的正确列中提取数据,给定列中的值:
SELECT years.*,
earthquakes.magnitude,
CASE year
WHEN 2000 THEN year_2000
WHEN 2001 THEN year_2001
WHEN 2002 THEN year_2002
WHEN 2003 THEN year_2003
WHEN 2004 THEN year_2004
WHEN 2005 THEN year_2005
WHEN 2006 THEN year_2006
WHEN 2007 THEN year_2007
WHEN 2008 THEN year_2008
WHEN 2009 THEN year_2009
WHEN 2010 THEN year_2010
WHEN 2011 THEN year_2011
WHEN 2012 THEN year_2012
ELSE NULL END
AS number_of_earthquakes
FROM tutorial.worldwide_earthquakes earthquakes
CROSS JOIN (
SELECT year
FROM (VALUES (2000),(2001),(2002),(2003),(2004),(2005),(2006),
(2007),(2008),(2009),(2010),(2011),(2012)) v(year)
) years
实例二
在SQL中,可以使用UNION ALL
操作符来将列转置为行。以下是一个简单的例子:
假设有一个表sales
,其结构如下:
year | product_a | product_b | product_c
-----|-----------|-----------|-----------
2017 | 100 | 200 | 150
2018 | 120 | 180 | 200
2019 | 150 | 220 | 250
转置后的结果将是:
year | product | sales
-----|----------|------
2017 | product_a| 100
2017 | product_b| 200
2017 | product_c| 150
2018 | product_a| 120
2018 | product_b| 180
2018 | product_c| 200
2019 | product_a| 150
2019 | product_b| 220
2019 | product_c| 250
以下是实现这一转置的SQL代码:
SELECT year, 'product_a' as product, product_a as sales FROM sales
UNION ALL
SELECT year, 'product_b', product_b FROM sales
UNION ALL
SELECT year, 'product_c', product_c FROM sales;
这段代码通过UNION ALL
将每个产品的销售数据行转换成三行,每行代表一个年份和对应的产品。