PostgreSQL - 相关子查询失败?

时间:2009-01-08 22:11:16

标签: sql database postgresql subquery

我有这样的查询:

SELECT t1.id,
    (SELECT COUNT(t2.id)
     FROM t2
     WHERE t2.id = t1.id
          ) as num_things
FROM t1
WHERE num_things = 5;

目标是获取在另一个表中出现5次的所有元素的id。但是,我收到了这个错误:

ERROR: column "num_things" does not exist
SQL state: 42703

我可能在这里做些傻事,因为我对数据库有些新意。有没有办法修复此查询,以便我可以访问num_things?或者,如果没有,是否还有其他方法可以实现这一结果?

5 个答案:

答案 0 :(得分:10)

关于使用SQL的一些要点:

  • 您不能在WHERE子句中使用列别名,但可以在HAVING子句中使用。这就是你得到错误的原因。
  • 您可以使用JOIN和GROUP BY比使用相关子查询更好地计算。它会快得多。
  • 使用HAVING子句过滤组。

以下是我编写此查询的方式:

SELECT t1.id, COUNT(t2.id) AS num_things
FROM t1 JOIN t2 USING (id)
GROUP BY t1.id
HAVING num_things = 5;

我意识到这个查询可以跳过JOIN和t1,就像Charles Bretana的解决方案一样。但我假设您可能希望查询包含来自t1的其他一些列。


回复:评论中的问题:

不同之处在于WHERE子句在行上进行评估,之后GROUP BY将组减少为每组一行。在组成立后评估HAVING子句。因此,您无法使用COUNT()更改群组的HAVING;你只能排除小组本身。

SELECT t1.id, COUNT(t2.id) as num
FROM t1 JOIN t2 USING (id)
WHERE t2.attribute = <value>
GROUP BY t1.id
HAVING num > 5;

在上面的查询中,WHERE过滤了与条件匹配的行,HAVING过滤了至少有五个计数的群组。

导致大多数人混淆的一点是,当他们没有GROUP BY子句时,似乎就像HAVINGWHERE是可以互换的。

在select-list中的表达式之前计算

WHERE。这可能并不明显,因为SQL语法首先放置select-list。因此,您可以使用WHERE限制行来节省大量昂贵的计算。

SELECT <expensive expressions>
FROM t1
HAVING primaryKey = 1234;

如果您使用上述查询,则会为每一行计算select-list中的表达式,但由于HAVING条件,只会丢弃大部分结果。但是,下面的查询仅计算与WHERE条件匹配的单行的表达式。

SELECT <expensive expressions>
FROM t1
WHERE primaryKey = 1234;

回顾一下,数据库引擎根据一系列步骤运行查询:

  1. 从表格生成一组行,包括JOIN生成的所有行。
  2. 根据行集评估WHERE条件,过滤掉不匹配的行。
  3. 在行集中为每个行计算select-list中的表达式。
  4. 应用列别名(请注意,这是一个单独的步骤,这意味着您不能在选择列表中的表达式中使用别名)。
  5. 根据GROUP BY子句,将每个组的一组压缩为一行。
  6. 针对群组评估HAVING条件,过滤掉不匹配的群组。
  7. 根据ORDER BY子句对结果进行排序。

答案 1 :(得分:3)

所有其他建议都有效,但要回答你的基本问题,写

就足够了
  SELECT id  From T2
  Group By Id
  Having Count(*) = 5

答案 2 :(得分:3)

我想提一下,在PostgreSQL中,没有办法在having子句中使用别名列。

SELECT usr_id AS my_id FROM user HAVING my_id = 1

不工作。

另一个不起作用的例子:

SELECT su.usr_id AS my_id,COUNT(*)AS val FROM sys_user AS su GROUP BY su.usr_id HAVING val&gt; = 1

会出现同样的错误:val列未知。

我很高兴这是因为Bill Karwin为Postgres写了一些不真实的东西:

“你不能在WHERE子句中使用列别名,但你可以在HAVING子句中使用。这就是你得到错误的原因。”

答案 3 :(得分:1)

我认为您可以像这样重写您的查询:

SELECT t1.id
FROM t1
WHERE (SELECT COUNT(t2.id)
     FROM t2
     WHERE t2.id = t1.id
          ) = 5;

答案 4 :(得分:0)

试试这个

SELECT t1.id,
    (SELECT COUNT(t2.id) as myCount
     FROM t2
     WHERE t2.id = t1.id and myCount=5
          ) as num_things
FROM t1