1

我有一个这样的查询:

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?或者,如果没有,有没有其他方法可以达到这个结果?

4

5 回答 5

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;

我意识到这个查询可以跳过JOINwith 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从句时,所以它看起来HAVING并且WHERE可以互换。

WHERE在选择列表中的表达式之前进行评估。这可能并不明显,因为 SQL 语法将选择列表放在首位。WHERE因此,您可以通过使用限制行来节省大量昂贵的计算。

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

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

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

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

  1. 从表中生成一组行,包括由 生成的任何行JOIN
  2. 根据行集评估WHERE条件,过滤掉不匹配的行。
  3. 在选择列表中为行集中的每个计算表达式。
  4. 应用列别名(注意这是一个单独的步骤,这意味着您不能在选择列表的表达式中使用别名)。
  5. GROUP BY根据子句,将组压缩为每组一行。
  6. 根据组评估HAVING条件,过滤掉不匹配的组。
  7. 根据ORDER BY子句对结果进行排序。
于 2009-01-08T22:18:48.893 回答
3

所有其他建议都可以,但是要回答您的基本问题,写下来就足够了

  SELECT id  From T2
  Group By Id
  Having Count(*) = 5
于 2009-01-08T22:18:51.720 回答
3

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

IE

从具有 my_id = 1 的用户中选择 usr_id 作为 my_id

不会工作。

另一个不起作用的例子:

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

会有同样的错误:val column is not known。

我强调这一点是因为 Bill Karwin 为 Postgres 写了一些不真实的东西:

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

于 2009-07-29T14:37:31.993 回答
1

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

SELECT t1.id
FROM t1
WHERE (SELECT COUNT(t2.id)
     FROM t2
     WHERE t2.id = t1.id
          ) = 5;
于 2009-01-08T22:15:39.587 回答
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
于 2009-01-08T22:20:57.470 回答