SQL,BigQuery - 用行的其他部分完成缺失值

Posted

技术标签:

【中文标题】SQL,BigQuery - 用行的其他部分完成缺失值【英文标题】:SQL, BigQuery - completing missing values with other part of rows 【发布时间】:2019-12-11 17:34:16 【问题描述】:

我正在使用导出到 BigQuery 的 Firebase 数据(数据包含来自移动应用程序的事件数据)。我已经对应用程序进行了更新,并且正在报告新参数。不幸的是,并非所有用户都拥有最新版本的应用程序。这就是为什么我有带有该参数的行以及没有它的行。

event_params 我有类似的东西:

| No | contentId | contentName         |
|----|-----------|---------------------|
| 1  | abc       | (parameter missing) |
| 2  | abc       | Name of ABC         |
| 3  | cde       | Name of CDE         |
| 4  | efg       | Name of EFG         |
| 5  | abc       | (parameter missing) |
| 6  | cde       | Name of CDE         |

现在,当我查询该表并指定(使用 UNNEST)我需要 contentName 参数时,我没有得到缺少该参数的行。 我有疑问:

SELECT
  ep.value.string_value as ContentID,
  ep2.value.string_value as ContentName,
  COUNT(1) as `Count`
FROM
  `mydataset.mytable.events_*`,
  UNNEST(event_params) as ep,
  UNNEST(event_params) as ep2
WHERE 
  event_name="my_event_name" AND
  ep.key="contentID" AND
  ep2.key="contentName"
GROUP BY 1,2

我得到:

| No | contentId | contentName | Count |
|----|-----------|-------------|-------|
| 1  | abc       | Name of ABC | 1     |
| 2  | cde       | Name of CDE | 2     |
| 3  | efg       | Name of EFG | 1     |

但是,我想得到:

| No | contentId | contentName | Count |
|----|-----------|-------------|-------|
| 1  | abc       | Name of ABC | 3     |
| 2  | cde       | Name of CDE | 2     |
| 3  | efg       | Name of EFG | 1     |

我想以某种方式完成缺少 contentName 参数的行,使用来自具有相同 contentId 的其他行的值(我们可以假设每个 contentId 具有相同的常量 contentName)

我怎样才能实现它?我想 SELF JOIN,但 BigQuery 不建议这样做。

【问题讨论】:

我的理解是,您的真正要求是您帖子最后一段的第二段 - 您应该展示您的输入数据和所需输出的示例 - 向我们展示您的中间故障排除数据 - 对我们没有多大帮助帮助你 - 但仍然很有价值,因为它提供了一些额外的信息 - 但主要信息仍然缺失 @MikhailBerlyant 我不明白你还有什么期望。我已经发布了我的 event_params 内容、我的查询、我想要的输出以及我通过当前查询获得的输出 - 你提到的所有内容 :) 这些示例如何支持您的以下语句“我想使用来自具有相同 contentId 的其他行的值以某种方式完成缺少 contentName 参数的行”?我不明白怎么做! 表格的每一行代表来自应用程序的一个事件。每行都有 event_params 数组。其中一些行在 event_params 中包含 contentName 参数,而其中一些行包含没有 contentName 的 event_params,但所有行都包含 contentId 参数。我想计算所有行(有和没有 contentName)——我可以只查询 contentID(所有行都包含它),但我还需要 contentName 值——这就是为什么我需要从包含这两个参数的行中获取它的原因。 我对UNNEST、event_params以及分析这些数据的理解来自:medium.com/firebase-developers/… 【参考方案1】:

Gordon 提供的解决方案可以稍作修改,以达到您想要的效果:

SELECT contentId.value.string_value as ContentID,
       MAX(contentName.value.string_value) as ContentName,
       COUNT(1) as `Count`
FROM `mydataset.mytable.events_*` e LEFT JOIN
      UNNEST(e.event_params) as contentId
      ON contentId.key = 'contentID' LEFT JOIN
      UNNEST(e.event_params) contentName
      ON contentName.key = 'contentName'
WHERE e.event_name = 'my_event_name'
GROUP BY 1;

请注意,我仅按 ContentID 进行分组,并且使用 MAX 聚合 ContentNames,忽略空值。

我已经重新创建了您的示例表,它按预期工作。

【讨论】:

【参考方案2】:

您可以更新表格以填充空值,然后进行查询

[1]

UPDATE `your_project.your_dataset.your_table` t_incomplete
SET t_incomplete.contentName = t_complete.contentName
FROM `your_project.your_dataset.your_table` t_complete
WHERE t_incomplete.contentId = t_complete.contentId
AND t_complete.contentName IS NOT NULL

我不确定这将如何与嵌套表一起使用,但您始终可以

    更新取消嵌套 使用查询 [1] 更新 更新嵌套

您可以通过这个示例 CREATE TABLE 来描绘背后的想法

CREATE TABLE  `your_project.your_dataset.sample_table`
(
  id INT64,
  nullable STRING
);

INSERT INTO `your_project.your_dataset.sample_table`
VALUES (1, 'foo');

INSERT INTO `your_project.your_dataset.sample_table`
VALUES (1, null);

INSERT INTO `your_project.your_dataset.sample_table`
VALUES (2, 'lel');

INSERT INTO `your_project.your_dataset.sample_table`
VALUES (1, null);

INSERT INTO `your_project.your_dataset.sample_table`
VALUES (2, null);

和查询[2]

UPDATE `your_project.your_dataset.sample_table` t_incomplete

SET t_incomplete.nullable = t_complete.nullable
FROM `wave27-sellbytel-aalbesa.trial_dataset.with_and_update` t_complete
WHERE t_incomplete.id = t_complete.id
AND t_complete.nullable IS NOT NULL

这样,您实际上为单元格提供了相应的值,您可以毫无顾虑地运行您的查询。我希望这行得通!

【讨论】:

不幸的是,更新表不是一种选择【参考方案3】:

您只需要OR 条件吗?

WHERE event_name = 'my_event_name' AND
      ep.key = 'contentID' AND
      (ep2.key = 'contentName' OR ep2.key IS NULL)

编辑:

我认为你需要LEFT JOINs:

SELECT contentId.value.string_value as ContentID,
       contentName.value.string_value as ContentName,
       COUNT(1) as `Count`
FROM `mydataset.mytable.events_*` e LEFT JOIN
      UNNEST(e.event_params) as contentId
      ON contentId.key = 'contentID' LEFT JOIN
      UNNEST(e.event_params) contentName
      ON contentName.key = 'contentName'
WHERE e.event_name = 'my_event_name'
GROUP BY 1, 2;

注意:这应该会保留您想要的计数,但可能会导致结果集中出现额外的行。

【讨论】:

不,通过您的查询,我得到的结果与我的查询相同。使用 (ep2.key="contentName" OR ep2.key IS NULL) 不会改变任何东西 - 不计算没有 contentName 参数的行。 关于更新的答案 - 我得到重复的行数(使用正确的 contentName 和 contentName=null)。我希望每个 contentId 只显示一次 - 使用正确的 contentName(取自包含这两个参数的行)。

以上是关于SQL,BigQuery - 用行的其他部分完成缺失值的主要内容,如果未能解决你的问题,请参考以下文章

按最新日期过滤 BigQuery 行的最有效方法

sql 已完成购买 - Google BigQuery

有没有办法使用预编译的 sql 完成工作并通过 java api (bigquery) 多次运行

Google BigQuery SQL:计算来自其他商店的用户

在BigQuery中封装复杂代码

BigQuery 文档 - 为啥 flatten 会消除重复