You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

PostgreSQL中如何通过多表连接实现按国家统计各流派的租赁次数?

最优实现方案:统计各国各流派的租赁次数

嘿,你的思路方向完全没问题——通过关联依赖表后分组统计就是核心解法,咱们先把逻辑捋顺,再聊聊你担心的「9表连接是否明智」这个问题。

先理清表的关联链路

咱们先把需要用到的表和关联关系拆解开,避免冗余连接:

  • 从租赁记录到国家的链路:rental → customer(通过customer_id)→ address(通过address_id)→ city(通过city_id)→ country(通过country_id)
  • 从租赁记录到流派的链路:rental → inventory(通过inventory_id)→ film(通过film_id)→ film_category(通过film_id)→ category(通过category_id)

没错,算下来确实是9张表,但只要连接逻辑正确,PostgreSQL处理这种量级的连接完全hold住——尤其是示例数据库里的外键默认都建了索引,性能不会有明显问题。

最终SQL实现(带注释)

下面是满足需求的最优查询语句,每一步都标了用途:

SELECT
    c.name AS category_name,  -- 流派名称
    co.country AS country_name,  -- 国家名称
    COUNT(r.rental_id) AS num_rentals  -- 用rental_id统计,避免把NULL算入
FROM
    rental r
-- 关联客户表,拿到客户的地址ID
INNER JOIN customer cu ON r.customer_id = cu.customer_id
-- 关联地址表,拿到城市ID
INNER JOIN address a ON cu.address_id = a.address_id
-- 关联城市表,拿到国家ID
INNER JOIN city ci ON a.city_id = ci.city_id
-- 关联国家表,拿到国家名称
INNER JOIN country co ON ci.country_id = co.country_id
-- 关联库存表,拿到对应影片ID
INNER JOIN inventory i ON r.inventory_id = i.inventory_id
-- 关联影片表,拿到影片的分类关联ID
INNER JOIN film f ON i.film_id = f.film_id
-- 关联影片分类中间表,拿到流派ID
INNER JOIN film_category fc ON f.film_id = fc.film_id
-- 关联流派表,拿到流派名称
INNER JOIN category c ON fc.category_id = c.category_id
-- 按流派+国家两个维度分组统计
GROUP BY
    c.name, co.country
-- 可选:按租赁次数降序,方便看热门组合
ORDER BY
    num_rentals DESC;

关键细节说明

  1. 连接类型选择:这里用INNER JOIN只会统计有实际租赁记录的国家+流派组合。如果需要覆盖「没有任何租赁的国家」或「从未被租赁的流派」,可以把对应位置的INNER JOIN改成LEFT JOIN,同时注意COUNT要保留r.rental_id(因为LEFT JOIN会产生NULL,COUNT(*)会把NULL也算进去,而COUNT(r.rental_id)只会统计有租赁记录的行)。
  2. 分组规则:必须把category.name和country.country都放进GROUP BY里,因为我们要按这两个维度做聚合统计。
  3. 性能优化:如果查询速度慢,可以检查这些外键字段的索引(示例数据库默认已建,但自定义库需要确认):rental.customer_id、rental.inventory_id、customer.address_id、address.city_id、city.country_id、inventory.film_id、film_category.film_id、film_category.category_id——索引能大幅提升多表连接的效率。
  4. 关于「9表连接是否明智」:只要是业务逻辑必需的连接,就完全没问题。PostgreSQL的查询优化器对这种链式连接的处理很成熟,不会因为表多就崩盘。反而把逻辑整合到一个查询里,比多次查询后在应用层聚合更高效,减少了数据库和应用之间的数据传输。

可选变体:统计所有国家(含无租赁的)

如果需要包含那些没有任何租赁记录的国家,可以调整连接顺序,从country开始做左连接:

SELECT
    c.name AS category_name,
    co.country AS country_name,
    COUNT(r.rental_id) AS num_rentals
FROM
    country co
LEFT JOIN city ci ON co.country_id = ci.country_id
LEFT JOIN address a ON ci.city_id = a.city_id
LEFT JOIN customer cu ON a.address_id = cu.address_id
LEFT JOIN rental r ON cu.customer_id = r.customer_id
LEFT JOIN inventory i ON r.inventory_id = i.inventory_id
LEFT JOIN film f ON i.film_id = f.film_id
LEFT JOIN film_category fc ON f.film_id = fc.film_id
LEFT JOIN category c ON fc.category_id = c.category_id
GROUP BY
    c.name, co.country
ORDER BY
    num_rentals DESC;

这种情况可能会出现category_name为NULL的行(对应没有任何影片租赁的国家),如果需要过滤掉,可以加WHERE c.name IS NOT NULL。


内容的提问来源于stack exchange,提问作者WHOATEMYNOODLES

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.30 18:12:49