在SQL中,如何查找每个用户的第一条记录(如果它在一个时间片内),而不扫描整个数据库

时间:2018-12-07 22:35:04

标签: sql amazon-redshift

我有一个数据库user_requests,基本上看起来像这样:

  user_id  |    request_timestamp    | request_type | other_metadata
-----------|-------------------------|--------------|----------------
  user1    |    2018-11-01:04:04:41  |    type1     | opaquedata_A
  user2    |    2018-11-01:04:03:41  |    type2     | opaquedata_B
  user1    |    2018-11-01:04:01:41  |    type1     | opaquedata_C
  user3    |    2018-11-01:04:05:41  |    type3     | opaquedata_D
  user4    |    2018-11-01:04:01:41  |    type4     | opaquedata_E

这是巨大。在整个事情上进行任何操作都是绝对站不住脚的,所有事情都需要像“哪个查询是本月最常见的”之类的,没有人会整体检查它。

我想做的是对几个用户的第一个请求进行一些分析。我绝对不需要每个用户的请求或所有时间的请求,只要它是代表性示例即可。

但是,我遇到的一个问题是,我通常会对此进行限制的所有尝试都是找到“范围内的第一个请求”而不是“如果范围内的第一个请求

SELECT DISTINCT user_id,
              first_value(request_type) over (PARTITION BY user_id ORDER BY request_timestamp
                rows BETWEEN unbounded preceding and unbounded following) requestType,
              first_value(other_metadata) over (PARTITION BY user_id ORDER BY request_timestamp
                rows BETWEEN unbounded preceding and unbounded following) otherMetadata,
              first_value(request_timestamp) over (PARTITION BY user_id ORDER BY request_timestamp
                rows BETWEEN unbounded preceding and unbounded following) utteranceTimestamp
FROM user_requests
WHERE request_timestamp BETWEEN '2018-11-01' AND request_timestamp < '2018-12-01'

像这样查找11月用户的最早请求,而我想要的是11月用户 overall 的最早请求。

有什么主意,尽管我仍然可以编写不需要花费数小时才能完成的查询,但是我如何得到想要的?

1 个答案:

答案 0 :(得分:1)

您想要调整形式的备用查询:

SELECT Curr.user_id, Curr.request_type, Curr.other_metadata, Curr.request_timestamp
FROM User_Requests Curr
WHERE  Curr.request_timestamp >='2018-11-01' 
       AND Curr.request_timestamp < '2018-12-01'
       AND NOT EXISTS (SELECT 1
                       FROM User_Requests Prev
                       WHERE Prev.user_id = Curr.user_id
                             AND Prev.request_timestamp < Curr.request_timestamp)

...这将查找给定时间范围内的所有请求,然后在一个月内或其他情况下,如果有 ANY 个较早的请求,则将其丢弃。这不仅是最早的一个月,而且还可以在需要的时间范围内忽略请求(如果还有其他先前的查询)。

为了获得最佳结果,您需要在(user_id, request_timestamp)上建立索引。
(请注意,我假设优化器很好,并将您的日期转换为用于范围搜索的适当类型。您可能要验证是否未强制request_timestamp进行铸造。)


奖金LEFT JOIN-排除形式,以防其表现更好。

SELECT Curr.user_id, Curr.request_type, Curr.other_metadata, Curr.request_timestamp
FROM User_Requests Curr
LEFT JOIN User_Requests Prev
       ON Prev.user_id = Curr.user_id
          AND Prev.request_timestamp < Curr.request_timestamp
WHERE  Curr.request_timestamp >='2018-11-01' 
       AND Curr.request_timestamp < '2018-12-01'
       AND Prev.user_id IS NULL