【问题标题】:Selecting a group with or without certain conditions across many rows in SQL在 SQL 中的多行中选择具有或不具有特定条件的组
【发布时间】:2019-02-27 19:34:45
【问题描述】:

我有这样的数据:

ID     SomeVar
123      0
123      1
123      2
234      1
234      2
234      3
456      3
567      0
567      1

我正在尝试按我的 ID 进行分组,以返回所有没有值 0 的记录的 ID。也就是说,我的选择如下所示:

ID
234
456

是否有一种简单的方法可以做到这一点,而无需创建所有记录不包含 0 的子表,然后将其加入到表不匹配的完整数据集中?

【问题讨论】:

    标签: sql hive impala


    【解决方案1】:

    我通常会尽量避免使用子查询,但在这种情况下您可以使用子查询。执行相同的分组,并检查 id 是否不在 SomeVar 为 0 的 id 的子查询中。在这种情况下, distinct 会做同样的事情并且更有效,所以我会先这样做:

    SELECT DISTINCT ID
    FROM [table_name]
    WHERE ID NOT IN (
        SELECT ID FROM [table_name] WHERE SomeVar = 0
    );
    

    如果您想使用 GROUP BY 获取其他信息:

    SELECT ID, max(SomeVar), count(*), sum(SomeVar)
    FROM [table_name]
    WHERE ID NOT IN (
        SELECT ID FROM [table_name] WHERE SomeVar = 0
    )
    GROUP BY ID;
    

    【讨论】:

    • 您有什么特别的原因要避免子查询?
    • @DukeLuke,如果您处理大量数据,通常效率低下。它通常也可以通过左连接和检查空值的条件来完成,但在这种情况下不是。只要您没有海量数据集,您的情况正是子查询的优势所在。
    • @mtr.web 在 Hive NOT IN 子查询中的工作方式与 LEFT JOIN + WHERE is NULL 过滤器相同。您的解决方案是两次表扫描 + 连接 + 不同的聚合。聚合 + HAVING 过滤器是更高效的解决方案。子查询还不错。连接和额外的扫描是不好的。
    【解决方案2】:

    你可以使用聚合和having:

    select id
    from t
    group by id
    having min(somevar) > 0;
    

    这假定somevar 永远不会是负数。如果这是可能的,那么您可以使用稍微详细一点的:

    select id
    from t
    group by id
    having sum(case when somevar = 0 then 1 else 0 end) = 0;
    

    【讨论】:

      【解决方案3】:

      使用计数或求和聚合的用例语句,使用having按计数过滤:

      select ID  
        from
            ( 
             select ID, count(case when SomeVar=0 then 1 end) cnt
               from mytable
              group by ID having count(case when SomeVar=0 then 1 end) = 0 
            ) s
      ;
      

      【讨论】:

        猜你喜欢
        • 2018-12-24
        • 1970-01-01
        • 2016-01-11
        • 1970-01-01
        • 1970-01-01
        • 2020-01-31
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多