我有一个数据库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 的最早请求。
有什么主意,尽管我仍然可以编写不需要花费数小时才能完成的查询,但是我如何得到想要的?
答案 0 :(得分:1)
您想要调整形式的备用greatest-n-per-group查询:
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