在Hive QL中使用DATEDIFF进行LEFT OUTER JOIN

时间:2013-09-25 17:45:58

标签: sql database-design join hive hiveql

我有两张桌子:让我们称他们为INSTALLS和EXECUTES。

INSTALLS表的结构为:user_id BIGINT,install_ts BIGINT。

EXECUTES表具有相同的结构:user_id BIGINT,exec_ts BIGINT。

user_id很明显,_ts字段是以Unix纪元计算的秒数表示的时间戳。

这两个表的填充方式如下:

每次用户安装我的应用程序时,都会填充INSTALLS表。然后他可以卸载并重新安装,在这种情况下,同一用户的另一行会出现在此表中(但不同的是ts)。对于我的所有分析,我需要使用最早的安装时间戳。

每次用户使用我的应用程序时,都会填充EXECUTES表 - 包含user_id和执行时间。

我需要创建一个具有以下结构的汇总表:

日期,该日期的安装次数,后续日期的使用次数

这就是我解决问题的方法:

  1. 获取最早的安装日期:

    SELECT user_id,DATE(MIN(install_ts))AS install_date FROM INSTALLS GROUP BY user_id

  2. 获取执行日期(需要在给定日期内满足多次执行):

    SELECT user_id,DATE(exec_ts)AS exec_date FROM EXECUTES GROUP BY user_id,DATE(exec_ts)

  3. 将这两者结合起来:

    SELECT a.install_date,COUNT(a.user_id)AS install_count,COUNT(b.user_id)AS usage_count 从     (SELECT user_id,DATE(MIN(install_ts))AS install_date FROM INSTALLS GROUP BY user_id)a     LEFT OUTER JOIN     (SELECT user_id,DATE(exec_ts)AS exec_date FROM EXECUTES GROUP BY user_id,DATE(exec_ts))b     ON a.user_id = b.user_id GROUP BY a.install_date

  4. 这会计算所有使用我的应用程序的用户。从这个数据集中,我现在只需要提取那些在其安装日期的后续日期使用我的应用程序的用户。

    我考虑的一种方法是增加一个JOIN条件。当我这样做时,我得到(先查询,下面的错误):

    SELECT a.install_date, COUNT(a.user_id) AS install_count, COUNT(b.user_id) AS usage_count
    FROM
        (SELECT user_id, DATE(MIN(install_ts)) AS install_date FROM INSTALLS GROUP BY user_id) a
        LEFT OUTER JOIN
        (SELECT user_id, DATE(exec_ts) AS exec_date FROM EXECUTES GROUP BY user_id, DATE(exec_ts)) b
        ON a.user_id = b.user_id AND DATEDIFF(b.exec_date, a.install_date) = 1
    GROUP BY a.install_date
    
      

    在JOIN'1'中遇到左右别名

    我考虑的第二种方法是在WHERE子句中使用DATEDIFF:

    SELECT a.install_date, COUNT(a.user_id) AS install_count, COUNT(b.user_id) AS usage_count
    FROM
        (SELECT user_id, DATE(MIN(install_ts)) AS install_date FROM INSTALLS GROUP BY user_id) a
        LEFT OUTER JOIN
        (SELECT user_id, DATE(exec_ts) AS exec_date FROM EXECUTES GROUP BY user_id, DATE(exec_ts)) b
        ON a.user_id = b.user_id
    WHERE b.user_id IS NULL OR DATEDIFF(b.exec_date, a.install_date) = 1
    GROUP BY a.install_date
    

    但是我可以看出这是完全错误的 - 如果用户在第1天安装并在第3天返回,他将不会被计入install_count(因为他不会出现在连接表中)。所以现在我有点想法了。我对SQL有点新手,所以任何帮助都会非常感激。

2 个答案:

答案 0 :(得分:2)

如果我完全理解,结果行将包含日期,日期上唯一身份用户的安装次数,以及该日期后执行该程序的次数所有用户的安装 ..因此,每个日期有2种不同的计算方式。

我的解决方案从两个表的连接开始(没有您使用的分组),然后后续操作使用分析功能然后分组。在我的测试中,表格使用字符串类型,因此日期看起来像“2013-08-01”等,可以使用DATEDIFF。

我创建了一个中间连接结果表,但这可以很容易地汇总到最终查询中。此连接表将为每个用户安装一行,安装日期为1或0,表示第二天是否有执行。

create table i_e_join as
select i.user_id, i.install_ts,
       if (e.exec_ts is null OR (DATEDIFF(e.exec_ts,i.install_ts) > 1), 0,1)
         over (partition by i.user_id,i.install_ts) as has_exec
from tmp_installs i left outer join tmp_executes e on (i.user_id = e.user_id);

然后使用一个简单的group by来获取每个install_ts的结果:

select install_ts, count(distinct user_id) as install_count, 
       sum(has_exec) as usage_count from i_e_join
group by install_ts;

创建连接表的关键是使用分析函数计算has_exec字段,该字段在install_ts上查看用户的所有行。

答案 1 :(得分:1)

我自己解决了这个问题。我就这样做了:

SELECT x.install_date, COUNT(x.user_id) AS install_count, COUNT(y.user_id) AS usage_count
FROM (
    SELECT user_id, DATE(MIN(install_ts)) AS install_date FROM INSTALLS GROUP BY user_id
) x LEFT OUTER JOIN (
    SELECT a.user_id AS user_id, a.install_date AS install_date, b.exec_date AS exec_date
    FROM
        (SELECT user_id, DATE(MIN(install_ts)) AS install_date FROM INSTALLS GROUP BY user_id) a
        JOIN
        (SELECT user_id, DATE(exec_ts) AS exec_date FROM EXECUTES GROUP BY user_id, DATE(exec_ts)) b
        ON a.user_id = b.user_id
        WHERE DATEDIFF(b.exec_date, a.install_date) = 1
) y
GROUP BY x.install_date