SQL - BigQuery - 在多个列中使用 Group 和 MAX - 类似于数据透视表

Posted

技术标签:

【中文标题】SQL - BigQuery - 在多个列中使用 Group 和 MAX - 类似于数据透视表【英文标题】:SQL - BigQuery - Using Group & MAX in several columns - Similar to a pivot table 【发布时间】:2020-11-19 14:09:18 【问题描述】:

您将如何通过 SQL 处理此问题?举个例子吧

| id | type | score_a | score_b | score_c | label_a | label_b | label_c |
|----|------|---------|---------|---------|---------|---------|---------|
| 1  | A    | 0.9     |         |         | L1      |         |         |
| 1  | B    |         | 0.7     |         |         | L2      |         |
| 1  | B    |         | 0.2     |         |         | L3      |         |
| 1  | C    |         |         | 0.2     |         |         | L4      |
| 1  | C    |         |         | 0.18    |         |         | L5      |
| 1  | C    |         |         | 0.12    |         |         | L6      |
| 2  | A    | 0.6     |         |         | L1      |         |         |
| 2  | A    | 0.3     |         |         | L2      |         |         |

我想返回每个 typelabel_X 的最高分数,几乎就像一个数据透视表,但带有这些自定义列名。所以上面的结果会是这样的:

| id | type | score_a | label_a | score_b | label_b | score_c | label_c |
|----|------|---------|---------|---------|---------|---------|---------|
| 1  | A    | 0.9     | L1      | 0.7     | L2      | 0.2     | L4      |
| 2  | A    | 0.6     | L1      | NULL    | NULL    | NULL    | NULL    |

这样的事情是错误的,因为它会根据typelabel 产生两个结果

SELECT id,
  MAX(score_a) as score_a,
  label_a,
  MAX(score_b) as score_b,
  label_b as label_b,
  MAX(score_c) as score_c,
  label_c
FROM sample_table 
GROUP BY id, label_a, label_b, label_c

有没有一种简单的方法可以通过 SQL 做到这一点,我现在正在从 BigQuery 做这件事,并尝试了如 here 所述的数据透视表,但仍然没有运气如何将这些扁平化成一个包含几列的大行

还有其他想法吗?

更新

扩展BGM 提到的设计;该数据的来源是一个表格,格式如下:

| id | type | label | score |
|----|------|-------|-------|
| 1  | A    | L1    | 0.9   |
| 1  | B    | L2    | 0.7   |
| 1  | B    | L3    | 0.2   |
| 1  | C    | L4    | 0.6   |
| 1  | C    | L5    | 0.2   |

使用类似的查询将其转换为如本问题顶部所示的扁平状态

 SELECT id,
      type,
      MAX(CASE WHEN type = 'A' THEN score ELSE 0 END) as score_a,
      MAX(CASE WHEN type = 'B' THEN score ELSE 0 END) as score_b,
      MAX(CASE WHEN type = 'C' THEN score ELSE 0 END) as score_c,
      MAX(CASE WHEN model_type = 'theme' THEN label_score ELSE 0 END) as 
      -- labels
      (CASE WHEN type = 'A' THEN label ELSE '' END) as label_a,
      (CASE WHEN type = 'B' THEN label ELSE '' END) as label_b,
      (CASE WHEN type = 'C' THEN label ELSE '' END) as label_c,
    FROM table
    GROUP id, label_a, label_b, label_c

你认为中间步骤对于得到最终解决方案是不必要的吗?

【问题讨论】:

【参考方案1】:

您可以进行条件聚合。在 Big Query 中,数组很方便:

select
    id,
    max(score_a) score_a,
    array_agg(label_a order by score_a desc limit 1)[offset(0)] label_a,
    max(score_b) score_b,
    array_agg(label_b order by score_b desc limit 1)[offset(0)] label_b,
    max(score_c) score_c,
    array_agg(label_c order by score_c desc limit 1)[offset(0)] label_c
from mytable
group by id

注意:在设计方面,您不应该有多个列来存储每种类型的分数和标签;您已经有一个表示类型的列,因此您应该只有两列用于存储和类型。

【讨论】:

是的,我们确实有一个表格来存储每种类型的分数和标签,我在这个问题上粘贴的是该表格的投影,该表格在上面展开。你认为使用它作为基础而不是这个扩展版本会以某种方式简化查询吗? @maerick 。 . .您可能会针对您开始使用的数据提出一个 问题。它可能更易于使用。

以上是关于SQL - BigQuery - 在多个列中使用 Group 和 MAX - 类似于数据透视表的主要内容,如果未能解决你的问题,请参考以下文章

BigQuery:从多个嵌套列中选择 * 替换

如何在 BigQuery 的标准 SQL 中解析具有不同日期字符串的列中的值

满足其他列中的条件后,如何在 SQL BigQuery 中重置运行总计?

Google BigQuery SQL:从 JSON(列表和数组)中提取数据到列中

BigQuery:使用标准 SQL 查询多个数据集和表

根据另一列中的值更新 BigQuery 中的嵌套数组