如何在配置单元/SQL中的where/having子句(避免子查询)中使用min()

如何在配置单元/SQL中的where/having子句(避免子查询)中使用min(),sql,hive,hiveql,Sql,Hive,Hiveql,我有一大堆活动。对于每个用户,我希望统计在最早的类型B事件之前发生的类型A事件 我在寻找一个优雅的问题。使用了配置单元,因此无法执行子查询 Timestamp Type User ... A X ... A X ... B X ... A X ... A X ... A Y ... A Y ... A Y ... B

我有一大堆活动。对于每个用户,我希望统计在最早的类型B事件之前发生的类型A事件

我在寻找一个优雅的问题。使用了配置单元,因此无法执行子查询

Timestamp Type User 
...        A    X
...        A    X
...        B    X
...        A    X
...        A    X

...        A    Y
...        A    Y
...        A    Y
...        B    Y
...        A    Y
通缉结果:

User Count_Type_A 
X    2
Y    3
我无法通过执行以下操作获得“截止”时间戳:

Select User, min(Timestamp) 
Where Type=B 
Group BY User;
但是,我如何在下一个查询中使用这些信息,我想执行以下操作:

SELECT User, count(Timestamp) 
WHERE Type=A AND Timestamp<min(User.Timestamp_Type_B) 
GROUP BY User;
选择用户、计数(时间戳)

其中Type=A和Timestamp第一次更新:

为了回应Cilvic对这个答案的第一个评论,我根据在上找到的评论中建议的解决方法,将我的查询调整为以下内容:

选择[User],计数([Timestamp])为[Before_First_B_COUNT]
从[Dataset]主数据集
交叉连接(从[Dataset]中选择[User],min([Timestamp])[First\u B\u TS]
其中[Type]=“B”
分组依据[用户])子
其中main.[Type]=“A”
和(sub.[User]=main.[User])
和(main.[Timestamp]
原件:

试一试:

SELECT [User], COUNT([Timestamp]) AS [Before_First_B_Count]
FROM [Dataset] main
JOIN (SELECT [User], min([Timestamp]) [First_B_TS] FROM [Dataset]
    WHERE [Type] = 'B'
    GROUP BY [User]) sub 
        ON (sub.[User] = main.[User]) AND (main.[Timestamp] < sub.[First_B_TS])
WHERE main.[Type] = 'A'
GROUP BY main.[User]
选择[User],计数([Timestamp])为[Before_First_B_COUNT]
从[Dataset]主数据集
加入(从[Dataset]中选择[User],min([Timestamp])[First_B__TS]
其中[Type]=“B”
分组依据[用户])子
在(sub.[User]=main.[User])和(main.[Timestamp]

我尽了最大的努力遵循蜂巢语法。如果你有任何问题,请告诉我。我想知道您为什么希望/需要避免子查询。

通常,I+1 coge.soft的解决方案。这里再次供您参考:

SELECT [User], COUNT([Timestamp]) AS [Before_First_B_Count]
FROM [Dataset] main
JOIN (SELECT [User], min([Timestamp]) [First_B_TS] FROM [Dataset]
    WHERE [Type] = 'B'
    GROUP BY [User]) sub 
        ON (sub.[User] = main.[User]) AND (main.[Timestamp] < sub.[First_B_TS])
WHERE main.[Type] = 'A'
GROUP BY main.[User]
选择[User],计数([Timestamp])为[Before_First_B_COUNT]
从[Dataset]主数据集
加入(从[Dataset]中选择[User],min([Timestamp])[First_B__TS]
其中[Type]=“B”
分组依据[用户])子
在(sub.[User]=main.[User])和(main.[Timestamp]
但是,有几件事需要注意:

  • 没有B事件时会发生什么?假设您希望计算每个用户的所有A事件,在这种情况下,解决方案中指定的内部联接将不起作用,因为子表中没有该用户的条目。为此,您需要更改为左外部联接

  • 该解决方案还对数据进行2次传递—一次用于填充子表,另一次用于将子表与主表连接起来。根据您对性能和效率的看法,有一种替代方法,您可以通过一次数据传递来实现这一点。您可以使用配置单元的功能按用户分发数据,并编写一个自定义减速机,该减速机将使用您最喜欢的语言进行计数计算


  • @Cilvic,以上第二点是你为什么试图避免子查询(根据你问题的标题)?@coge.soft我不确定我是否明白你的意思。我认为你提出的解决方案有效。但同时它也很难理解/阅读。我希望找到更优雅/更容易阅读的东西。我需要先了解distribute by better。我发现hive(不幸的是)不支持<连接条件:“hive中只支持相等连接、外部连接和左半连接。hive不支持非相等条件的连接条件,因为很难将此类条件表示为映射/减少作业。”对不起,我又做了一次尝试。请让我知道它是否有效。简言之,我将ON语句移动到WHERE子句,并使(内部)连接成为交叉连接。
    SELECT [User], COUNT([Timestamp]) AS [Before_First_B_Count]
    FROM [Dataset] main
    JOIN (SELECT [User], min([Timestamp]) [First_B_TS] FROM [Dataset]
        WHERE [Type] = 'B'
        GROUP BY [User]) sub 
            ON (sub.[User] = main.[User]) AND (main.[Timestamp] < sub.[First_B_TS])
    WHERE main.[Type] = 'A'
    GROUP BY main.[User]