有效的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,分区是按时间块)

+0

您的子查询在语法上不正确。他们需要一个'from'子句。 –

我会调用表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; 

你可以加入回原来的数据(或使用INEXISTS),以获得详细的行,如果你喜欢。

+0

谢谢戈登!在两个评论。 – Nir

在原始尝试中,将IN更改为EXISTS

添加这些:

INDEX(condition_a, timestamp, user_id) 
INDEX(condition_b, timestamp, user_id) 

问题的说法是不准确的。 “从t1到t2有条件”是什么意思?

  • 一行与“a”的该时间范围存在,或所有这些的
  • 多行,其中一个具有“A”,或
  • 多个行,具有“A” ??

INEXISTS更昂贵,因为它必须找到所有行。 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)