有效的SQL查询来获取不同条件的行中的不同时间
问题描述:
假设我们有一个表users
: user_id, timestamp, condition_a, condition_b
有效的SQL查询来获取不同条件的行中的不同时间
每个用户会话与用户ID相同,不同的时间戳和任意条件和/或b一行。
我想去做查询:
- 用户谁了条件从T1到T2和NOT条件B从T3到T4。
- 在t3之前条件为a且条件b为b的用户。
一种方式来做到这一点是与子查询:
上面第一例子:
SELECT * FROM users WHERE
user_id IN
(SELECT user_id WHERE timestamp BETWEEN t1 AND t2 AND condition_a =1)
AND user_id NOT IN
(SELECT user_id WHERE timestamp BETWEEN t2 AND t3 AND condition_b =1)
这看起来非常低效的我,因为它必须扫描表几次。
有没有更有效的方法来做到这一点,只需要扫描表一次? (这是为了最终presto,分区是按时间块)
答
我会调用表sessions
,而不是用户。所以,我们从这里开始。如果您有一个表users
,则user_id
应该是主键(或类型2维中的自然键)。
一种方法来获取user_ids
是聚集:
SELECT s.user_id
FROM sessions s
WHERE (timestamp BETWEEN t1 AND t2 AND condition_a = 1) OR
(timestamp BETWEEN t2 AND t3 AND condition_b = 1)
GROUP BY s.user_id
HAVING SUM(timestamp BETWEEN t1 AND t2 AND condition_a = 1) > 0 AND
SUM(timestamp BETWEEN t2 AND t3 AND condition_b = 1) > 0;
你可以加入回原来的数据(或使用IN
或EXISTS
),以获得详细的行,如果你喜欢。
+0
谢谢戈登!在两个评论。 – Nir
答
在原始尝试中,将IN
更改为EXISTS
。
添加这些:
INDEX(condition_a, timestamp, user_id)
INDEX(condition_b, timestamp, user_id)
问题的说法是不准确的。 “从t1到t2有条件”是什么意思?
- 一行与“a”的该时间范围存在,或所有这些的
- 多行,其中一个具有“A”,或
- 多个行,具有“A” ??
IN
比EXISTS
更昂贵,因为它必须找到所有行。 EXISTS
只处理前两个含义。
对于第二个问题,我建议
SELECT u.*
FROM users AS u
WHERE EXISTS (SELECT * FROM ... WHERE condition_a AND timestamp < t1
AND user_id = u.user_id)
AND EXISTS (SELECT * FROM ... WHERE condition_b AND timestamp > t3
AND user_id = u.user_id)
连同
INDEX(user_id, condition_a, timestamp)
INDEX(user_id, condition_b, timestamp)
这可能会更好(用于获取user_ids),并就只需要我的第一配对索引:
(SELECT DISTINCT user_id FROM ... WHERE condition_a AND timestamp < t1)
UNION ALL -- 'ALL' is deliberate, for GROUP and HAVING
(SELECT DISTINCT user_id FROM ... WHERE condition_b AND timestamp > t3)
GROUP BY user_id
HAVING COUNT(*) = 2
获取用户信息:
SELECT u.*
FROM (that union) AS v
JOIN users AS u USING(user_id)
您的子查询在语法上不正确。他们需要一个'from'子句。 –