2017-01-25 31 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