HAVING子句没有按SELECT中的所有非聚合列进行分组

时间:2013-03-19 18:07:33

标签: sql sas proc-sql

HAVING子句没有按SELECT中的所有非聚合列分组 我经常遇到具有id列和月份列以及许多其他指标的表。我根据其他列清除了某些行。我只想要拥有所有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语句中没有聚合函数?

4 个答案:

答案 0 :(得分:2)

这取决于数据库。在我的一个(redbrick)上,你提出的查询会抛出一个错误。为了使它工作,我必须改变

select * 

select id.  

然而,你可能有误入歧途的动机。我通常对获得正确答案的最有效方法感兴趣。对自己和任何可能需要维护它的人来说,清晰也很重要,但对外行的清晰度不是我的优先事项之一。

答案 1 :(得分:1)

当使用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 这并不总是强制执行(取决于实施)或要求(取决于具体情况),但我总是喜欢可预测的结果。

答案 2 :(得分:1)

当然,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
在幕后。没有技术原因可以不这样做,除非您的工作现场要求有干净的日志(在这种情况下您不会)。它不是非常冒险,但与此同时,为什么不明确地写入连接?

答案 3 :(得分:1)

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