获取 GROUP BY 后的行数

Get the count of rows count after GROUP BY

这是我在 Rails 项目的 Ruby 中使用的代码,用于查找 residences 其中 amenitiesids 48、49 和50.他们通过连接has_many连接起来。

id_list = [48, 49, 50]
Residence.joins(:listed_amenities).
          where(listed_amenities: {amenity_id: id_list}).
          group('residences.id').
          having("count(listed_amenities.*) = ?", id_list.size)

结果SQL:

SELECT "residences".*
FROM "residences"
INNER JOIN "listed_amenities" ON "listed_amenities"."residence_id" = "residences"."id"
WHERE "listed_amenities"."amenity_id" IN (48, 49, 50)
GROUP BY residences.id
HAVING count(listed_amenities.*) = 3

我想知道此查询产生的 residences 的数量。有没有办法添加 count 或其他东西让数据库进行计算?我不想在 Ruby 中这样做会浪费计算能力。添加 .count 方法不起作用。结果是 {528747=>3, 529004=>3, 529058=>3}.

如果您的设计强制执行参照完整性,则您根本不必为此目的加入 table residences。还假设 UNIQUEPK(residence_id, amenity_id) 的约束(否则你需要不同的查询!)

最佳查询取决于您的需要完全

使用 window 函数,您 甚至可以 在单个查询级别中执行此操作:

SELECT count(*) OVER () AS ct
FROM   listed_amenities
WHERE  amenity_id IN (48, 49, 50)
GROUP  BY residence_id
HAVING count(*) = 3
LIMIT  1;

此 window 函数将总计数附加到每一行而不聚合行。考虑 SELECT 查询中的事件序列:

  • Best way to get result count before LIMIT was applied

因此,您可以对 return 所有符合条件的 ID(甚至整行)使用类似的查询,并将计数附加到每一行(冗余):

SELECT residence_id, count(*) OVER () AS ct
FROM   listed_amenities
WHERE  amenity_id IN (48, 49, 50)
GROUP  BY residence_id
HAVING count(*) = 3;

但最好使用子查询,那是 通常便宜得多:

SELECT count(*) AS ct
FROM  (
   SELECT 1
   FROM   listed_amenities
   WHERE  amenity_id IN (48, 49, 50)
   GROUP  BY residence_id 
   HAVING count(*) = 3
   ) sub;

您可以同时 return 一组 ID(与上面的 set 相对),因为几乎没有更多的成本:

SELECT array_agg(residence_id ) AS ids, count(*) AS ct
FROM  (
   SELECT residence_id 
   FROM   listed_amenities
   WHERE  amenity_id IN (48, 49, 50)
   GROUP  BY residence_id
   HAVING count(*) = 3
   ) sub;

还有许多其他变体,您必须阐明预期结果。喜欢这个:

SELECT count(*) AS ct
FROM   listed_amenities l1
JOIN   listed_amenities l2 USING (residence_id)
JOIN   listed_amenities l3 USING (residence_id)
WHERE  l1.amenity_id = 48
AND    l2.amenity_id = 49
AND    l2.amenity_id = 50;

基本上是关系除法的情况。我们在这里汇集了一系列技术:

  • How to filter SQL results in a has-many-through relation