获取 GROUP BY 后的行数
Get the count of rows count after GROUP BY
这是我在 Rails 项目的 Ruby 中使用的代码,用于查找 residences
其中 amenities
与 ids
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
。还假设 UNIQUE
或 PK
对 (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
这是我在 Rails 项目的 Ruby 中使用的代码,用于查找 residences
其中 amenities
与 ids
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
。还假设 UNIQUE
或 PK
对 (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