多个表每周的 SQL 计数摘要

标签 sql postgresql left-join

我有一个 SQL,可以生成过去 365 天的一系列星期:

SELECT
  to_char(weekdate, 'YYWW') as yearWeek
FROM
GENERATE_SERIES(
  NOW()::DATE-EXTRACT(DOW FROM NOW())::INTEGER-365,
  NOW()::DATE-EXTRACT(DOW from NOW())::INTEGER,
  '1 week'
) AS t(weekdate)

然后,我使用时间戳列加入“team_a”表中每周计数的摘要(“LEFT OUTER JOIN”考虑计数为 0 的周):

SELECT
  to_char(weekdate, 'YYWW') as yearWeek,
  count(a.timestamp) AS team_a_total
FROM
GENERATE_SERIES(
  NOW()::DATE-EXTRACT(DOW FROM NOW())::INTEGER-365,
  NOW()::DATE-EXTRACT(DOW from NOW())::INTEGER,
  '1 week'
) AS t(weekdate)
LEFT OUTER JOIN team_a a
  ON to_char(weekdate, 'YYWW') = to_char(a.timestamp, 'YYWW')
GROUP BY to_char(weekdate, 'YYWW')
ORDER BY yearWeek

这工作正常,结果符合预期,但我想加入“team_b”表中的另一个计数摘要,我认为这是添加另一个“LEFT OUTER JOIN”的简单情况,如下所示:

SELECT
  to_char(weekdate, 'YYWW') as yearWeek,
  count(a.timestamp) AS team_a_total,
  count(b.timestamp) AS team_b_total
FROM
GENERATE_SERIES(
  NOW()::DATE-EXTRACT(DOW FROM NOW())::INTEGER-365,
  NOW()::DATE-EXTRACT(DOW from NOW())::INTEGER,
  '1 week'
) AS t(weekdate)
LEFT OUTER JOIN team_a a
  ON to_char(weekdate, 'YYWW') = to_char(a.timestamp, 'YYWW')
LEFT OUTER JOIN team_b b
  ON to_char(weekdate, 'YYWW') = to_char(b.timestamp, 'YYWW')
GROUP BY to_char(weekdate, 'YYWW')
ORDER BY yearWeek

但是结果不正确。 “team_a_total”和“team_b_total”列似乎显示了两列的乘积

例如,对于“1628”周(2016 年第 28 周),“team_a_total”的总计应为 8,“team_b_total”的总计应为 36,但两列显示的结果均为 288,即 8x36。

我做错了什么?

感谢您的回答。根据 Laurenz 的代码,这对我有用(以及 Hambone 的答案):

---------------------------
SELECT weekdate,
  team_a_total,
  count(b.timestamp) AS team_b_total
FROM
(
  SELECT
    to_char(weekdate, 'YYWW') AS weekdate,
    count(a.timestamp) AS team_a_total
  FROM
  GENERATE_SERIES(
    NOW()::DATE-EXTRACT(DOW FROM NOW())::INTEGER-365,
    NOW()::DATE-EXTRACT(DOW from NOW())::INTEGER,
    '1 week'
  ) AS t(weekdate)
  LEFT OUTER JOIN team_a a ON to_char(a.timestamp, 'YYWW') = to_char(weekdate, 'YYWW')
  GROUP BY to_char(weekdate, 'YYWW')
) subq
LEFT OUTER JOIN team_b b ON to_char(b.timestamp, 'YYWW') = weekdate
GROUP BY weekdate, team_a_total
ORDER BY weekdate
---------------------------

最佳答案

我认为一些子查询可能会修复它:

with a as (
  select
    to_char(timestamp, 'YYWW') as week,
    count (*) as cnt
  from team_a
  group by week
),
b as (
  select
    to_char(timestamp, 'YYWW') as week,
    count (*) as cnt
  from team_b
  group by week
),
s as (
  SELECT
    to_char(weekdate, 'YYWW') as yearWeek
  FROM
  GENERATE_SERIES(
    NOW()::DATE-EXTRACT(DOW FROM NOW())::INTEGER-365,
    NOW()::DATE-EXTRACT(DOW from NOW())::INTEGER,
    '1 week'
  ) AS t(weekdate)
)
SELECT
  s.yearWeek,
  coalesce (a.cnt, 0) as team_a_total,
  coalesce (b.cnt, 0) as team_b_total
FROM
  s
  LEFT JOIN a on s.yearWeek = a.week
  left join b on s.yearWeek = b.week
ORDER BY s.yearWeek

问题是您进行了迷你笛卡尔连接,即您将该周的 team_a 中的每条记录与同一周 team_b 中的每条记录连接起来。

所以,如果你有这个:

   team_a              team_b
   1633    x           1633       a
   1633    y           1633       b
   1633    z

您的联接将产生 6 条记录。

x-a
x-b
y-a
y-b
z-a
z-c

通过将它们隔离在子查询中,您可以聚合它们,然后连接聚合结果。

子查询 s 并不是完全必要的,但我认为它使它看起来更干净。

关于多个表每周的 SQL 计数摘要,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/41849883/

相关文章:

sql - 将 SQL 消息输出到日志文件

mysql优先选择一个值

sql - 更新表格的日期和月份

django - 当角色实际存在时, 'role does not exist' 错误怎么可能

Mysql 左连接右表中的条件

where条件下的Mysql别名

mysql - 如何更新 bit(10) 数据类型列?

sql - 制定 SQL 语句

php - 具有多个 COUNT() 的多个 LEFT JOINS 对所有列进行计数

MySQL 排除与连接表匹配的记录(行)