如何删除子选择中的相关子查询(由于presto限制)

时间:2016-10-28 06:31:18

标签: sql hive correlated-subquery presto

我试图在过去约2个月的14天滚动窗口内找到来自美国的已经执行特定操作(p.action中的任何行)的用户的明显计数。

这是查询。我喜欢一些关于我如何重写它以不使用相关子查询的提示,因为Presto不允许它们。

SELECT dt,
    (SELECT COUNT(DISTINCT user_id)
     FROM p.action
     WHERE dt BETWEEN q.dt - 13 AND q.dt -- period of 14 days
        AND country = 'US'
     ) AS 14d_rolling_users
FROM p.action q
WHERE dt BETWEEN '2016-08-24' AND '2016-10-24'  
GROUP BY dt
ORDER BY dt ASC

我一直绞尽脑汁试图找出如何在不运行60个单独查询的情况下完成此任务(每天一个)。

感谢任何帮助,谢谢!

2 个答案:

答案 0 :(得分:1)

不具备presto的经验,但从逻辑上讲,您可以重写您的查询,以p.action进行笛卡尔积加入(无条件加入){2}个日约束p.action使用相同的2个飞蛾日期约束,那么你就不需要内部查询。

SELECT dt,COUNT(DISTINCT user_id)
FROM p.action q1,p.action q2  
WHERE q1.dt BETWEEN '2016-08-24' AND '2016-10-24'  
  AND q2.dt BETWEEN '2016-08-24' AND '2016-10-24' 
  AND q1.dt BETWEEN q2.dt - 13 AND q2.dt -- period of 14 days
  AND country = 'US'
GROUP BY q1.dt
ORDER BY q1.dt ASC

预先创建2个月的表会更有效 - 这里的条件是在加入后应用的。

答案 1 :(得分:1)

最好进行手动汇总。

这会将表格中的每一行变为14行,并带有额外的rollup__ds个时间戳。然后,我们按此新列进行分组,以创建一个滚动的14天窗口。这种复杂性是O(N*14) = O(N),因而是线性的。

SELECT 
  rollup__ds,
  COUNT(DISTINCT username)
FROM (
  SELECT
    username,
    ds
  FROM
    actions
  WHERE 
    ds BETWEEN '2016-08-24' AND '2016-10-24'
    AND country = 'US'
)
CROSS JOIN 
  UNNEST(ARRAY[
    DATE_ADD('day', 0, CAST(ds AS DATE)),
    DATE_ADD('day', 1, CAST(ds AS DATE)),
    ...
    DATE_ADD('day', 12, CAST(ds AS DATE)),
    DATE_ADD('day', 13, CAST(ds AS DATE))
  ]) AS t (rollup__ds)
GROUP BY 
  rollup__ds
ORDER BY 
  rollup__ds
;

希望有所帮助!

NB- 如果你不需要明显的计数最好使用一个窗口函数,唉这不适用于不同的计数,因为它们不能像那样求和。

SELECT 
  ds, 
  -- BEWARE this count is NOT distinct!
  SUM(COUNT(username)) over (ORDER BY ds ROWS BEWTEEN 13 PRECEDING AND CURRENT ROW) 
FROM
  actions
WHERE
  ds BETWEEN '2016-08-24' AND '2016-10-24'
  AND country = 'US'
;