多个用户的左外连接

Left outer join for multiple users

我有一个高尔夫球回合的数据库。我想看看去年每个用户每个月有多少回合。

为此,我使用此代码

创建了此视图 last_12_months
SELECT date_part('month'::text, dates.date) AS month,
    date_part('year'::text, dates.date) AS year
FROM ( SELECT (generate_series((now() - '1 year'::interval), now(), '1 mon'::interval))::date AS date) dates;
month year
1 2020
2 2020
and so on to ...
12 2020

统计轮次的汇总视图也很简单rounds_count_by_users

user_id month year count_all
1 1 2020 15
1 3 2020 12
1 5 2020 10
2 4 2020 7
2 8 2020 6
2 9 2020 3

现在,对于我想要的,使用 left outer join 查询每个用户非常简单

select * 
from last_12_months
left outer join rounds_count_by_users
  on last_12_months.month = rounds_count_by_users.month
  and last_12_months.year = rounds_count_by_users.year
  and user_id = 1

这给了我所有的月份,即使用户没有玩过几轮。然而,我想要的是能够为每个用户执行此操作,并制作一个物化视图以便于查询。有没有一种简单易行的方法来做到这一点?要清楚这是我想要的最终 table。

这个查询至少不起作用,就我所知。

select * 
from last_12_months
left outer join rounds_count_by_users
  on last_12_months.month = rounds_count_by_users.month
  and last_12_months.year = rounds_count_by_users.year
where user_id = 1
user_id month year count_all
1 1 2020 15
1 2 2020 null
1 3 2020 12
1 4 2020 null
1 5 2020 10
1 6 2020 null
1 7 2020 null
1 8 2020 null
1 9 2020 null
1 10 2020 null
1 11 2020 null
1 12 2020 null
2 1 2020 null
2 2 2020 null
2 3 2020 null
2 4 2020 7
2 5 2020 null
2 6 2020 null
2 7 2020 null
2 8 2020 6
2 9 2020 3
2 10 2020 null
2 11 2020 null
2 12 2020 null

我为此做了一个 SQL Fiddle(值略有不同,但架构相同)

PS:我知道 table 别名和数据建模等等。我的问题完全是关于如何实现最终结果。

这个查询:

select * from last_12_months
where (year = year(current_date) - 1 and month >= month(current_date))
      or 
      (year = year(current_date) and month < month(current_date))

returns 最近 12 个月(不包括当前月份)last_12_months 的行。

这个查询:

select distinct user_id from rounds_count_by_users

returns 所有不同的 user_id(如果这些 ID 存储在 users table 中会更好)。

您必须 CROSS 加入上述查询,然后 LEFT 加入 rounds_count_by_users:

select u.user_id, m.month, m.year, r.count_all  
from (
  select * from last_12_months
  where (year = year(current_date) - 1 and month >= month(current_date))
        or 
        (year = year(current_date) and month < month(current_date))
) m cross join (select distinct user_id from rounds_count_by_users) u
left outer join rounds_count_by_users r
on m.month = r.month and m.year = r.year and u.user_id = r.user_id
order by u.user_id, m.month

参见demo

所以我在评论中提供帮助后设法做到了这一点。 这让我得到了我想要的。

with all_rows as (
  select * from view_last_12_months inner join users on true
)

select id as user_id, all_rows.year, all_rows.month, count_all
from all_rows left outer join view_rounds_count_last_year last12 
  on last12.month = all_rows.month 
    and last12.year = all_rows.year
    and all_rows.id = last12.user_id