【问题标题】:How to find aggregate value for rows in a table in different range of values in Bigquery?如何在 Bigquery 的不同值范围内查找表中行的聚合值?
【发布时间】:2022-06-19 02:17:25
【问题描述】:

我有一个 bigquery 表,格式为 company_id、date、sales_amount。 sales_amount 是一个 FLOAT64 列,其值可以从 0 到 10 亿不等。我需要为每个 company_id 找到第一次达到特定 sales_amount 范围的第一个日期。

到目前为止,我所写的是每个范围都使用了 with 子句:

With A as (
SELECT company_id, min(date) breakDate
FROM <table>
WHERE sales_amount >= 100000 and sales_amount < 500000
GROUP BY company_id
),
B as (
SELECT company_id, min(date) breakDate
FROM <table>
WHERE sales_amount >= 500000 and sales_amount < 1000000
GROUP BY company_id
),
AllUnion AS (
SELECT * FROM A
LEFT JOIN B
USING(company_id)
WHERE B.breakDate > A.breakDate OR B.company_id is NULL

UNION ALL
SELECT * FROM B
)

因此,当添加新范围时,我必须添加一个新的 With 部分,并在最后一个大的 union 部分合并所有中断事件。在合并时,我将确保如果先发生高阶事件,则过滤掉低阶事件。例如,在这种情况下,一家公司在 1 月份(第一次)的销售额超过 500K,而他们的销售额在 2 月份下降并达到 120K。只有 500K 的销售额事件将被返回,2 月的事件将被过滤掉

我必须为不同的表执行此操作,并且可能有更多事件,我想知道是否有一种聪明的方法可以在 bigquery 中编写此查询?

【问题讨论】:

    标签: google-bigquery


    【解决方案1】:

    您可以对桶中的sales_amount 进行分桶,使其具有相同的桶 id。然后通过company_id和bucket_id分组,就可以得到每个bucket的MIN(date)。

    SELECT company_id, MIN(date) AS breakDate 
      FROM <table>
     WHERE sales_amount >= 100000 
     GROUP BY company_id, RANGE_BUCKET(sales_amount, [100000, 500000, 1000000]);
    

    例子:

    WITH sales AS (
      SELECT 'c1' AS company_id, '2022-05-01' AS date, 99999 AS sales_amount
       UNION ALL
      SELECT 'c1' AS company_id, '2022-05-02' AS date, 100000 AS sales_amount
       UNION ALL
      SELECT 'c1' AS company_id, '2022-05-03' AS date, 499999 AS sales_amount
       UNION ALL
      SELECT 'c1' AS company_id, '2022-05-04' AS date, 500000 AS sales_amount
       UNION ALL
      SELECT 'c1' AS company_id, '2022-05-05' AS date, 1100000 AS sales_amount
    )  
    SELECT company_id, 
           buckets[SAFE_OFFSET(RANGE_BUCKET(sales_amount, buckets) - 1)] AS bucket_id,
           MIN(sales_amount) AS sales_amount,
           MIN(date) AS breakDate
      FROM sales, UNNEST([STRUCT([100000, 500000, 1000000] AS buckets)])
     WHERE sales_amount >= 100000 
     GROUP BY company_id, bucket_id
    ;
    

    输出:

    示例 2:

    WITH sales AS (
      SELECT 'c1' AS company_id, '2022-05-01' AS date, 99999 AS sales_amount
       UNION ALL
      SELECT 'c1' AS company_id, '2022-05-02' AS date, 100000 AS sales_amount
       UNION ALL
      SELECT 'c1' AS company_id, '2022-05-03' AS date, 499999 AS sales_amount
       UNION ALL
      SELECT 'c1' AS company_id, '2022-05-05' AS date, 1100000 AS sales_amount
       UNION ALL
      SELECT 'c1' AS company_id, '2022-05-07' AS date, 500000 AS sales_amount
    ),
    bucketized_sales AS (
      SELECT company_id, 
             buckets[SAFE_OFFSET(RANGE_BUCKET(sales_amount, buckets) - 1)] AS bucket_id,
             MIN(sales_amount) AS sales_amount,
             MIN(date) AS breakDate
        FROM sales, UNNEST([STRUCT([100000, 500000, 1000000] AS buckets)])
       WHERE sales_amount >= 100000 
       GROUP BY company_id, bucket_id
    )
    SELECT *, MAX(bucket_id) OVER (PARTITION BY company_id ORDER BY breakDate ROWS  BETWEEN  UNBOUNDED PRECEDING AND 1 PRECEDING)  factor
      FROM bucketized_sales 
     WHERE TRUE QUALIFY bucket_id > factor OR factor IS NULL
     ORDER BY breakDate
    ;
    

    输出:

    【讨论】:

    • 有没有办法可以将存储桶信息添加到选择查询中以了解它是哪个存储桶?还过滤掉高阶之后的低阶事件。前公司首先达到 50 万销售额,然后销售额下降并在下个月达到 10 万。所以在这种情况下过滤掉 100K 事件。
    • 我已更新查询以显示您的第一个问题的存储桶信息。
    • 嘿,谢谢,它非常适合我。现在我唯一想知道的是,早些时候我加入了“with 语句”并过滤掉了在高销售额事件之后发生的低销售额事件。
    • 对于第二个问题,我假设总销售额会随着时间的推移而增加。如果您正在考虑净销售额,您可能需要另一种方法来获得您想要的结果。
    • 销售就像那一天的销售。它不是累积的。
    猜你喜欢
    • 1970-01-01
    • 2020-12-01
    • 2021-08-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多