SQL数据分析 之 在 SQL 中转置数据实例

阅读 20

2024-11-13

SQL数据分析 之 在 SQL 中转置数据实例_数据

转置即旋转数据表的横纵方向,常用来改变数据布局,以便用新的角度观察,下面主要给大家介绍关于SQL行列转置以及非常规行列转置.

在SQL查询中转换和转置数据(非数字)可以通过使用CASE语句和聚合函数来实现。

转换数据是指将行数据转换为列数据,可以使用CASE语句将不同的值转换为不同的列。

将行转置为列

下面我们将尝试如何获取格式化数据以进行分析,并对其进行透视以进行演示或绘制图表。

实例一

原数据集

SQL数据分析 之 在 SQL 中转置数据实例_SQL_02

我们想使其看起来像这样:

SQL数据分析 之 在 SQL 中转置数据实例_SQL_03

让我们首先聚合数据,以显示每个联盟中每年的玩家数量:

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年,全球地震的数量

SQL数据分析 之 在 SQL 中转置数据实例_数据_04

在这种格式中,回答诸如“地震的平均震级是多少”之类的问题是具有挑战性的。如果数据显示在 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将每个产品的销售数据行转换成三行,每行代表一个年份和对应的产品。

精彩评论(0)

0 0 举报