【问题标题】:PARTITION BY in CASE doesn't work with several AND statementsCASE 中的 PARTITION BY 不适用于多个 AND 语句
【发布时间】:2018-12-13 19:30:29
【问题描述】:

我有一个包含 4 列的表:hitId、userId、timestamp 和 Camp。 我需要使用两个参数来分类命中是否是新会话的开始(1 或 0):1. 命中之间的时间差和 2. 如果命中的来源是新的广告系列。

我需要 BigQuery 中的标准 SQL 查询。

如果满足以下条件之一,则认为一次命中是新会话的开始:

  1. 这是来自其 userId 的第一个命中
  2. 上一次命中的时间戳与 相同的 userId 超过 30 分钟。
  3. 同一个userId上一次命中的时间戳之间的时间差小于30分钟,但是Camp(广告活动)值不为NULL,并且在前30分钟内对于同一个userId第一次出现。

所以如果来自user1的hit1的Camp等于Campaign1,来自user1的hit2的Camp等于Campaign1,并且hit1和hit2之间的时间差小于30分钟,hit1将被认为是一个会话的开始,并且 hit2 不会被视为开始。

我在广告系列部分遇到问题。我试过这段代码:

我试过这段代码:

WITH timeDifference AS (
  SELECT *, 
  TIMESTAMP_DIFF(timestamp, LAG(timestamp, 1) OVER
          (PARTITION BY userId ORDER BY timestamp), SECOND) AS difference
    FROM hitTable
      ORDER BY timestamp)
SELECT *, 
  CASE 
  WHEN difference >= 30 * 60 THEN 1 
  WHEN difference IS NULL THEN 1 
  WHEN difference <= 30 * 60 AND Camp IS NOT NULL AND RANK() 
  OVER (PARTITION BY userId ORDER BY Camp) = 1 THEN 1
  ELSE 0 END AS sess
  FROM timeDifference
  ORDER BY timestamp;

条件RANK() OVER (PARTITION BY userId ORDER BY Camp) 似乎不起作用,因为我收到了这张表:

hitId | userId |  timestamp   |  Camp           |  difference  |  sess
_______________________________________________________________________
00150 | 858201 | 00:48:35.315 |  NULL           |  NULL        |  1
00151 | 858201 | 00:49:35.315 |  NULL           |  5           |  0
00152 | 858201 | 00:50:35.315 |  Search-Ads-US  |  10          |  0
00153 | 858201 | 00:53:35.315 |  Search-Ads-US  |  15          |  0
00154 | 858202 | 00:54:35.315 |  Facebook-Ads   |  NULL        |  1
00155 | 858202 | 00:54:55.315 |  Facebook-Ads   |  9           |  0
00156 | 858202 | 00:57:20.315 |  Facebook-Ads   |  12          |  0

虽然我希望 sess 列的 hitId = 00152 有 1:

hitId | userId |  timestamp   |  Camp           |  difference  |  sess
_______________________________________________________________________
00150 | 858201 | 00:48:35.315 |  NULL           |  NULL        |  1
00151 | 858201 | 00:49:35.315 |  NULL           |  5           |  0
00152 | 858201 | 00:50:35.315 |  Search-Ads-US  |  10          |  1
00153 | 858201 | 00:53:35.315 |  Search-Ads-US  |  15          |  0
00154 | 858202 | 00:54:35.315 |  Facebook-Ads   |  NULL        |  1
00155 | 858202 | 00:54:55.315 |  Facebook-Ads   |  9           |  0
00156 | 858202 | 00:57:20.315 |  Facebook-Ads   |  12          |  0

【问题讨论】:

    标签: sql session google-bigquery partitioning


    【解决方案1】:

    此 RANK() OVER (PARTITION BY userId ORDER BY Camp) 在用户拥有多个 Camp 的情况下返回错误结果。

    当您想在每个 Camp 中标记会话时,请注意您的 PARTITION BY 使用 userId。

    对于 userId 00150 的 RANK() (...) 语句的实际“排名 1”是 Camp 为 NULL (hitId 00150) 的位置,因此它错过了 hitId 00152 处的 CASE 条件。

    您可以尝试将“Camp”添加到您的 PARTITION BY 中,如下所示: RANK() OVER (PARTITION BY userId, Camp ORDER BY Camp)

    或者,除了您正在计算的 LAG(timestamp) (...) 之外,您还可以替换 RANK() (...) 并使用 LAG(Camp) (... order by timestamp)。 这将检索前行的 Camp 值(称为“PreviousCampValue”)。然后你可以添加类似 WHEN PreviousCampValue != Camp THEN 1

    希望对你有帮助

    【讨论】:

    • LAG(Camp) 完全按照需要工作。非常感谢您的详细解释!
    猜你喜欢
    • 2021-04-03
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-04-02
    • 2018-07-22
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多