错误:标量子查询生成多个元素

Wil*_*uks 4 google-bigquery

我们刚开始将查询从Legacy迁移到Standard SQL,因此我们现在正在学习如何处理嵌套数据和数组.

基本上我们想要做的是从ga_sessions表中检索以下数据:

visitor id, session id, array of skus
visitor 1, session 1, [sku_0, sku_1, (...), sku_n]
visitor 1, session 2, [skus]
Run Code Online (Sandbox Code Playgroud)

为此,我们运行了这个简单的查询:

  WITH
  customers_data AS(
  SELECT
    fullvisitorid fv,
    visitid v,
    ARRAY_AGG((
      SELECT
        prods.productsku
      FROM
        UNNEST(hits.product) prods)) sku
  FROM
    `dataset_id.ga_sessions_*`,
    UNNEST(hits) hits
  WHERE
    1 = 1
    AND _table_suffix BETWEEN FORMAT_DATE("%Y%m%d", DATE_SUB(CURRENT_DATE(), INTERVAL 1 DAY))
    AND FORMAT_DATE("%Y%m%d", DATE_SUB(CURRENT_DATE(), INTERVAL 0 DAY))
    --and (select count(productsku) from unnest(hits.product) where productsku is not null) = 1
  GROUP BY
    fv,
    v
  LIMIT
    100 )
SELECT
  *
FROM
  customers_data
Run Code Online (Sandbox Code Playgroud)

但是我们得到了这个错误:

Error: Scalar subquery produced more than one element
Run Code Online (Sandbox Code Playgroud)

来自该hits字段的数据如下所示:

在此输入图像描述

所以当我们补充where条款时:

and (select count(productsku) from unnest(hits.product) where productsku is not null) = 1
Run Code Online (Sandbox Code Playgroud)

它没有给出错误,但结果重复了skus,我们也丢失了更大数组内的skus.

我们的查询中是否存在一些错误,导致阵列无法使用?

Ell*_*ard 8

如果我理解正确,我想你想要这样的东西:

WITH customers_data AS (
  SELECT
    fullvisitorid fv,
    visitid v,
    ARRAY_CONCAT_AGG(ARRAY(
      SELECT productsku FROM UNNEST(hits.product))) sku
  FROM
    `dataset_id.ga_sessions_*`,
    UNNEST(hits) hits
  WHERE
    _table_suffix BETWEEN
      FORMAT_DATE("%Y%m%d", DATE_SUB(CURRENT_DATE(), INTERVAL 1 DAY))
      AND FORMAT_DATE("%Y%m%d", DATE_SUB(CURRENT_DATE(), INTERVAL 0 DAY))
  GROUP BY
    fv,
    v
  LIMIT
    100
)
SELECT
  *
FROM
  customers_data;
Run Code Online (Sandbox Code Playgroud)

这通过使用提取每行的SKU ARRAY_CONCAT_AGGARRAY子查询来保留所有SKU .如果要跨行对所有SKU进行重复数据删除,则可以替换

SELECT
  *
FROM
  customers_data;
Run Code Online (Sandbox Code Playgroud)

有:

SELECT *
  REPLACE (ARRAY(SELECT DISTINCT s FROM UNNEST(sku) AS s) AS sku)
FROM
  customers_data;
Run Code Online (Sandbox Code Playgroud)

编辑:有关更多阅读,请查看文档中的表达式子查询类型.在您的情况下,您需要一个ARRAY子查询,因为我们的想法是ARRAY<STRUCT<...>>在每一行中取一个并将其转换ARRAY为字段类型,以便跨行连接数组.

ARRAY_AGG从单个元素ARRAY_CONCAT_AGG创建一个数组,而从数组的串联创建一个数组.它们之间的区别是类似于数组文本构造之间的差[]ARRAY_CONCAT,除了_AGG版本聚集函数.

作为一个独立的示例,您可以尝试:

WITH T AS (
  SELECT ARRAY<STRUCT<x INT64, y INT64>>[(1, 10), (2, 11), (3, 12)] AS arr UNION ALL
  SELECT ARRAY<STRUCT<x INT64, y INT64>>[(4, 13)] UNION ALL
  SELECT ARRAY<STRUCT<x INT64, y INT64>>[(5, 14), (6, 15)]
)
SELECT ARRAY(SELECT x FROM UNNEST(arr)) AS x_array
FROM T;
Run Code Online (Sandbox Code Playgroud)

这将返回一个列x_array,其中每个数组中的元素是x来自每个元素的字段中的元素arr.要连接所有数组以便结果中有一行,请使用ARRAY_CONCAT_AGG,例如:

WITH T AS (
  SELECT ARRAY<STRUCT<x INT64, y INT64>>[(1, 10), (2, 11), (3, 12)] AS arr UNION ALL
  SELECT ARRAY<STRUCT<x INT64, y INT64>>[(4, 13)] UNION ALL
  SELECT ARRAY<STRUCT<x INT64, y INT64>>[(5, 14), (6, 15)]
)
SELECT ARRAY_CONCAT_AGG(ARRAY(SELECT x FROM UNNEST(arr))) AS x_array
FROM T;
Run Code Online (Sandbox Code Playgroud)

对于您的其他问题,请REPLACE接受与要替换的列配对的表达式列表.表达式可以是简单的,例如文字,或者它可以是更复杂的东西,例如ARRAY子查询,这是我使用的.例如:

WITH T AS (
  SELECT 1 AS x, 'foo' AS y, true AS z UNION ALL
  SELECT 2, 'bar', false UNION ALL
  SELECT 3, 'baz', true
)
SELECT * REPLACE(1 - x AS x, CAST(x AS STRING) AS y)
FROM T;
Run Code Online (Sandbox Code Playgroud)

这将替换原有xy将已经从被返回的列SELECT *与结果1 - xCAST(x AS STRING)替代.