PostgreSQL - 相关子查询失败?
-
06-07-2019 - |
题
我有一个这样的查询:
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
?或者,如果没有,还有其他方法可以达到这个结果吗?
解决方案
我认为您可以像这样重写您的查询:
SELECT t1.id
FROM t1
WHERE (SELECT COUNT(t2.id)
FROM t2
WHERE t2.id = t1.id
) = 5;
其他提示
关于使用 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
筛选计数至少为 5 的组。
导致大多数人困惑的一点是当他们没有 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;
回顾一下,数据库引擎根据一系列步骤运行查询:
- 从表中生成行集,包括由
JOIN
. - 评价
WHERE
针对行集的条件,过滤掉不匹配的行。 - 为行集中的每一行计算选择列表中的表达式。
- 应用列别名(请注意,这是一个单独的步骤,这意味着您不能在选择列表的表达式中使用别名)。
- 将组压缩为每组一行,根据
GROUP BY
条款。 - 评价
HAVING
针对组的条件,过滤掉不匹配的组。 - 对结果进行排序,根据
ORDER BY
条款。
所有其他建议都有效,但要回答你的基本问题,写
就足够了 SELECT id From T2
Group By Id
Having Count(*) = 5
我想提一下,在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写了一些不真实的东西:
&quot;您不能在WHERE子句中使用列别名,但您可以在HAVING子句中使用。这就是你得到错误的原因。“
试试这个
SELECT t1.id,
(SELECT COUNT(t2.id) as myCount
FROM t2
WHERE t2.id = t1.id and myCount=5
) as num_things
FROM t1