PostgreSQL在哪里计算条件

时间:2011-11-14 09:26:16

标签: sql postgresql group-by having

我在PostgreSQL中有以下查询:

SELECT 
    COUNT(a.log_id) AS overall_count
FROM 
    "Log" as a, 
    "License" as b 
WHERE 
    a.license_id=7 
AND 
    a.license_id=b.license_id 
AND
    b.limit_call > overall_count
GROUP BY 
    a.license_id;

为什么我会收到此错误:

  

错误:列“overall_count”不存在

我的表结构:

License(license_id, license_name, limit_call, create_date, expire_date)
Log(log_id, license_id, log, call_date)

我想检查许可证是否已达到特定月份的通话限制。

3 个答案:

答案 0 :(得分:45)

SELECT a.license_id, a.limit_call
     , count(b.license_id) AS overall_count
FROM   "License"  a
LEFT   JOIN "Log" b USING (license_id)
WHERE  a.license_id = 7 
GROUP  BY a.license_id  -- , a.limit_call  -- add in old versions
HAVING a.limit_call > count(b.license_id)

重点

  • 在PostgreSQL 9.1之前的版本中,您必须将limit_call添加到 GROUP BY 子句中。 从版本9.1开始,在GROUP BY子句中使用主键就足够了。 release notes for 9.1

      

    主要时,在查询目标列表中允许非GROUP BY列   key在GROUP BY子句

    中指定
  • 您的WHERE条件必须移至 HAVING 子句,因为它引用了聚合函数的结果。并且您不能在HAVING子句中引用输出列(列别名),其中您只能引用输入列。所以你必须重复表达。 Per documentation:

      

    输出列的名称可用于引用列的值   ORDER BYGROUP BY条款,但不在WHEREHAVING条款中;   那里你必须写出表达式。

  • 我颠倒了FROM子句中表的顺序,并稍微清理了语法,使其不那么混乱。 USING 在这里只是一种符号方便。

  • 我使用 LEFT JOIN 代替JOIN,因此您根本不会排除没有任何日志的许可。

  • 如果可能,我建议在Postgres中使用mixed case identifiers。非常容易出错。

  • count()仅计算非空值。由于您要在表"Log"中计算相关条目,因此使用 count(b.license_id) 会更安全且更便宜。此列用于连接,因此我们无需担心列是否为空 count(*)更短,速度更快。如果您不介意在左表中为1行计算0,请使用它。

答案 1 :(得分:6)

where查询无法识别您的列别名,而且,您尝试在聚合后过滤行。尝试:

SELECT 
COUNT(a.log_id) AS overall_count
FROM 
"Log" as a, 
"License" as b 
WHERE 
a.license_id=7 
AND 
a.license_id=b.license_id 
GROUP BY 
a.license_id
having b.limit_call > count(a.log_id);

having子句与where子句类似,不同之处在于它处理聚合后的列,而where子句在聚合之前处理列。

另外,您的表名是否有用双引号括起来的原因?

答案 2 :(得分:2)

纯条件计数(*):

  SELECT COUNT(*) FILTER(where a.myfield > 0) AS my_count
    FROM "Log" as a 

GROUP BY a.license_id

所以你:

  • 为条件从不满足的组获取0
  • 可以根据需要添加任意数量的count(*)列

筛选出条件不匹配的组:

注意:除非使用HAVING b.limit_call > ...分组,否则不能使用limit_call。但是,您可以使用聚合函数将组中的许多“ limit_calls”映射为单个值。例如,您可以使用MAX

  SELECT COUNT(a.log_id) AS overall_count
    FROM "Log" as a 
    JOIN "License" b ON(a.license_id=b.license_id)

GROUP BY a.license_id
  HAVING MAX(b.limit_call) > COUNT(a.log_id)

不要在第一行和最后几行中复制COUNT(a.log_id)表达式。 Postgres将对其进行优化。