2017-01-25 33 views
2

我有一个生成从过去的365天系列星期的SQL:SQL计数摘要多个表

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”表我认为这是一个简单的情况下添加另一个“左外联接”像这样:

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',但这两列显示的结果是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 
--------------------------- 

回答

2

我觉得有些子查询可能会解决它:

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 

的你有会产生六个记录加入。

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

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

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

+0

几乎工作除了几个错字的的:“系列为” =>“ s as“和”a.cnt as team_b_total“=>”b.cnt as team_b_total“。此外,结果显示空白/无数星期没有计数;如何将它们改为0? – Jason

+0

是的 - 很好的错别字。我认为我解决了这个问题。此外,要获得零而不是null,请使用'coalesce'。我编辑了所有这三个项目的答案(拼写错误+合并)。 – Hambone

1

执行的逻辑顺序是:先加入,然后过滤,然后分组,然后排序。

第一次连接之后,您将获得一周多行(分组尚未完成),并且如果添加第二个连接,则这些行中的每一行都会连接到新表。所以你最终的产品。做

一种方法是使用子查询来迫使第一GROUP BY第二前进行加盟:

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 ... t(weekdate) 
      LEFT OUTER JOIN team_a ON ... 
     GROUP BY to_char(weekdate, 'YYWW') 
    ) subq 
    LEFT OUTER JOIN team_b ON ... 
GROUP BY weekdate, team_a_total 
ORDER BY weekdate; 
+0

非常好,感谢您解释由于SQL中的事件序列而导致的意外结果的原因。 – Jason