【问题标题】:HAVING clause without grouping by all non-aggregate columns in SELECT没有按 SELECT 中的所有非聚合列分组的 HAVING 子句
【发布时间】:2013-03-19 18:07:33
【问题描述】:

HAVING 子句不按SELECT 中的所有非聚合列分组 我经常遇到具有 id 列和 month 列以及许多其他指标的表。我根据其他列清除了某些行。我只想找出拥有全部 12 个月数据的 ID,所以我执行以下操作:

proc sql;
   create table t as
   SELECT *
   FROM  T1
   GROUP BY id
   HAVING COUNT(id) = 12
quit;

这似乎对我有用,但我想知道这种方法是否有任何危险。我知道我可以加入只有 id 和 id 计数的聚合子查询,但这种方法更容易向非 sql 用户解释。

一般来说,您可以使用HAVING 子句,在GROUP BY 中只有几列,而在SELECT 语句中没有聚合函数吗?

【问题讨论】:

    标签: sql sas proc-sql


    【解决方案1】:

    这取决于数据库。在我的一个(红砖)上,您提出的查询将引发错误。为了让它发挥作用,我必须改变

    select * 
    

    select id.  
    

    但是,您可能有错误的动机。我通常对获得正确答案的最有效方法感兴趣。对我自己和任何可能需要维护它的人来说清楚也很重要,但对非专业人士来说清楚并不是我的首要任务之一。

    【讨论】:

    • 当您选择所有列并按其中之一分组时,PROC SQL (SAS) 不会引发错误。
    • 我并不感到惊讶。 sql 中的 s 表示结构化,而不是标准。另外,我认为您不会发布崩溃的查询。
    • 感谢大家的反馈。在上面的示例中,我查看每个组中的行的顺序无关紧要,因为我只想要一个计数。在这种特殊情况下,以这种方式使用 have 不会造成任何伤害……对吧?更一般地说,如果我想对特定 id 的行进行平均或求和,那也不重要……对吗?如果我开始尝试选择最大值或最小值,我会遇到麻烦。至少我是这么理解的。
    【解决方案2】:

    当使用 GROUP BY 子句时,所选值必须1来自为组选择的列之一或聚合函数的结果。这是因为在关系代数模型中不能保证会选择哪条记录 - 某些 SQL 方言,例如 SQL Server,会拒绝这样的构造并出现错误!

    现在,假设我们希望 所有记录 负责使这个条件成立(即“选择非分组/聚合列”),我们可以使用连接。连接是一种简单的处理方式,展示了 RA,但不同的数据库可能支持具有不同结构的相同结果。

    select t.* from (
      select id
      from T1
      group by id
      having count(id) = x) as g
    left join T1 as t
    on t.id = g.id
    

    但是,这与以下(在 SQL Server 中无效)不同

    select * -- ONLY the id column value is "well-defined" !!
    from T1
    group by id
    having count(id) = x
    

    因为在后一种情况下,每个组只选择一个记录。这也是为什么只使用定义组或从该组聚合的列才有意义的原因。


    1 这并不总是强制执行(取决于实施)或要求(取决于具体情况),但我一直喜欢可预测的结果。

    【讨论】:

      【解决方案3】:

      SAS 将允许您这样做,当然,在其 SQL 实现中(您的标签表明您正在使用 SAS 的实现)。您将在日志中收到一条注释:

      NOTE: The query requires remerging summary statistics back with the original data

      SAS 实际上执行与pst 的答案相同的查询:

      select t.* from (
        select id
        from T1
        group by id
        having count(id) = x) as g
      left join T1 as t
      on t.id = g.id
      

      幕后。没有技术上的理由不这样做,除非您在工作现场要求拥有干净的日志(在这种情况下您不会)。风险不是很大,但同时,为什么不明确写下join呢?

      【讨论】:

        【解决方案4】:
        select t.* from (
          select id
          from T1
          group by id
          having count(id) = x) as g
        left join T1 as t
        on t.id = g.id
        

        【讨论】:

          猜你喜欢
          • 2016-07-28
          • 1970-01-01
          • 1970-01-01
          • 2020-10-15
          • 2017-12-22
          • 1970-01-01
          • 1970-01-01
          • 2013-01-23
          • 1970-01-01
          相关资源
          最近更新 更多