如何在子查询的 WHERE 子句中使用来自 UNNEST 的多个值?

Posted

技术标签:

【中文标题】如何在子查询的 WHERE 子句中使用来自 UNNEST 的多个值?【英文标题】:How do you use multiple values from UNNEST in WHERE clause of a subquery? 【发布时间】:2020-01-29 14:23:52 【问题描述】:

在 BigQuery 上使用标准 SQL,我试图从列中仅选择某些值,具体取决于存储在同一记录的数组中的值。

例如,每条记录都包含 event_timestamp 列和一组用户属性。我只想为满足特定用户属性的事件选择 event_timestamps,例如key = 'Level_Number' 和 value.string_value = '04';但我需要为同一个表中的多个用户属性执行此操作,例如时间戳,其中 value.string_value = '04' 在一个字段中,然后 value.string_value ='05' 在下一个字段中。

问题是,当我尝试这样做时,我得到了错误:“标量子查询产生了多个元素”。

例如,这些是我尝试过的查询:

SELECT
user_pseudo_id AS user_id,
(SELECT TIMESTAMP_MICROS(event_timestamp) from `analytics_161693185.events_*`
  WHERE EXISTS 
      (SELECT value.string_value FROM UNNEST (user_properties) WHERE key = "Level_Number" AND value.string_value = '02'))  AS time_turned_02,   
FROM `analytics_161693185.events_*`
SELECT
user_pseudo_id AS user_id,
(SELECT TIMESTAMP_MICROS(event_timestamp) from `analytics_161693185.events_*`
  WHERE
      (SELECT value.string_value FROM UNNEST (user_properties) WHERE key = "Level_Number") = '02')  AS time_turned_02,   
FROM `analytics_161693185.events_*`
SELECT
user_pseudo_id AS user_id,
(SELECT TIMESTAMP_MICROS(event_timestamp) from `analytics_161693185.events_*`
  WHERE
      (SELECT key FROM UNNEST (user_properties)) = 'Level_Number'
      AND (SELECT value.string_value FROM UNNEST (user_properties)) = '02') AS time_turned_02,   
FROM `analytics_161693185.events_*`

但是他们都给出了同样的错误。

我知道一种解决方案是使用类似于以下的代码创建临时表:

WITH
temporary_table_02 AS(
SELECT
user_pseudo_id AS user_id,
TIMESTAMP_MICROS(event_timestamp) AS time_turned_02,
FROM `analytics_161693185.events_*`
WHERE (SELECT value.string_value FROM UNNEST(user_properties) WHERE key = "Level_Number") = '02' 
),

这然后允许您从这些表中选择值并将它们连接到一个新表中,但由于有 18 个级别,创建 18 个临时表会导致 BigQuery 说查询过于复杂,因此此解决方案不可行。

如果它有助于使事情更清楚,这里是一个数据示例: Data Sample

这是一个电子表格,显示了我希望从简化架构中看到的预期结果。 https://docs.google.com/spreadsheets/d/1QGsp5ko54ZtRIdYejoA3tcJ99PCml6dL7sMRJRdLQzc/edit?usp=sharing

【问题讨论】:

【参考方案1】:

你把一些括号弄错了,你不需要unnest的FROM子句

SELECT
user_pseudo_id AS user_id,
TIMESTAMP_MICROS(event_timestamp) 
from `analytics_161693185.events_*`
  WHERE EXISTS 
      (
       SELECT 1 FROM UNNEST (user_properties) 
       WHERE key = "Level_Number" AND value.string_value = '02'
      )
  AND EXISTS 
      (
       SELECT 1 FROM UNNEST (user_properties) 
       WHERE key = "another key" AND value.string_value = '03'
      )

【讨论】:

感谢您的回复,但您发布的解决方案将 WHERE 子句置于 SELECT 部分之外,这意味着我只能选择该表中的时间戳,然后我将无法在同一个表中选择 value.string_value = '03' 的时间戳。 这仍然会选择满足这两个条件的所有时间戳到一个字段中。我需要 value.string_value = '02' 的时间戳进入一列,而 value.string_value = '03' 的时间戳进入另一列。 为什么会有不同的时间戳?在您的架构中,该行只有一个时间戳。发布一个简单的 CSV 表和预期结果示例,因为有些不清楚。 是的,该行只有一个时间戳,但是用户可以有许多行具有不同的 Level_Number 值,我需要将 Level_Number 为 03 的时间戳放入一列,并将时间戳记Level_Number 是 02 进入不同的列。 docs.google.com/spreadsheets/d/…【参考方案2】:

您可以像这里一样在 SELECT 语句中添加标量查询

SELECT
    user_pseudo_id AS user_id,
    TIMESTAMP_MICROS(event_timestamp),
    (SELECT value.string_value FROM UNNEST(user_properties) WHERE key = 'Level_Number' LIMIT 1) as LevelNumber
FROM `analytics_161693185.events_*`
WHERE EXISTS (SELECT 1 FROM UNNEST (user_properties) WHERE key = "Level_Number")

【讨论】:

通过将时间戳与 LevelNumbers 并排放置在列中,这很有效,但是,如果我想在单个表中选择,不同的列存储不同 LevelNumbers 的时间戳,我我仍然不确定该怎么做。 IE。 user_id 的列,然后是该 user_id 的时间戳列,其中 LevelNumber 为 2,然后是该 user_id 的时间戳列,其中 LevelNumber 为 3,依此类推。 不要那样做。将它们保持为行。为什么需要它们作为列?告诉你到底需要什么,然后我们可以构造最终的查询。 在帖子的最后,我添加了一个电子表格,显示了预期结果的外观,我需要它们作为列,因为我将在我想要搜索的新查询中使用时间戳两个时间戳之间的记录,例如记录时间戳在 02 列和 03 列之间的时间戳。 @AlfieBrae 我从整个对话和电子表格中的预期输出中了解到,您需要每个 user_id 出现两次,相同的列但不同的条目(行)。一个用于 LevelNumber = 2,一个用于 LevelNumber = 3,它们将具有不同的 event_timestamp 但相同的 user_id。我认为当你说你需要它们在不同的列中而不是你指的是不同的条目(行)时,你会造成一些混乱。你能确认一下吗? 我会有一个包含 user_id、level、timestamp 列的长表。然后在 Excel、Data Studio 或 Python 中旋转它。无论你喜欢什么。您可以将 user_id 用作索引变量,将 level 用作枢轴变量。

以上是关于如何在子查询的 WHERE 子句中使用来自 UNNEST 的多个值?的主要内容,如果未能解决你的问题,请参考以下文章

在子查询中使用内联函数(在 WHERE 子句中)

在子查询中为数据透视列的值实现 WHERE 子句?

sql面试题_SQl优化技巧_1注意通配符中like的使用,百分号放后面_2避免在where子句中对字段进行函数操作_3在子查询当中,尽量用exists代替in_4where子句中尽量不要使用(代码片

如何在子查询中使用 select 中的值?

来自给定数组的查询中的 Laravel 多个 where 子句

Hive:在连接之前在子表中使用 where 子句是不是会提高性能?