2015-09-21 76 views
0

我嘗試從包含日誌記錄信息的表中生成一些用戶統計信息。Postgres遞歸CTE或交叉表函數

**TABLE users** 
user_id | user_name 
------------------- 
1  | julia 
2  | bob 
3  | sebastian 


**TABLE logs** 
user_id | action  | timepoint 
------------------------------------ 
1  | create_quote | 2015-01-01 
1  | send_quote | 2015-02-03 
1  | create_quote | 2015-02-02 
1  | start_job  | 2015-01-15 
2  | start_job  | 2015-02-23 
2  | send_quote | 2015-03-04 
2  | start_job  | 2014-12-02 

我的期望輸出如下表

user_id | username | create_quote | send_quote | start_job 
----------------------------------------------------------- 
1  | julia  |2    | 1   | 1 
2  | bob  |0    | 1   | 1 
3  | sebastian |0    | 0   | 0 

它包括所有用戶(即使沒有任何記錄),但只有日期「2015年1月1日」的行動和「2015年-05-31' 。操作按操作類型和用戶進行計數/分組。

的SQL語句可能看起來像

SELECT * FROM myfunction() WHERE to_char(timepoint, 'YY/MM') BETWEEN '15/01' AND '15/05'; 

成才,你有什麼想法如何管理呢?我一直在嘗試使用CTE和遞歸以及交叉表功能,但找不到任何解決方案。

+1

你只有這三個動作? create_quote,send_quote和start_job? –

+0

@a_horse_with_no_name現在我只有這三個動作。但未來可能會有不同的 – Sebastian

+0

看起來你一直在試圖對我的答案進行編輯......如果你有評論或問題,只需將其添加到我的回覆下面或編輯你的問題來澄清。我發現你在我的代碼中發現了一個錯誤,現在已經糾正了,是的 - 我不喜歡這個函數的想法,但是我做到了,因爲我認爲你的文章暗示你想要一個函數(儘管我承認我不確定)。請參閱修訂... – Hambone

回答

1

我認爲交叉表函數會更加優雅,但是如果您沒有加載擴展或像我一樣與語法糾纏的話,這是一種笨拙的,蠻力的方式你可以這樣做:

CREATE OR REPLACE FUNCTION get_stats(
    from_date date, 
    thru_date date) 
    RETURNS table (
    user_id integer, 
    username text, 
    create_quote bigint, 
    send_quote bigint, 
    start_job bigint 
) AS 
$BODY$ 
    select 
    l.user_id, u.username, 
    sum (case when action = 'create_quote' then 1 else 0 end) as create_quote, 
    sum (case when action = 'send_quote' then 1 else 0 end) as send_quote, 
    sum (case when action = 'start_job' then 1 else 0 end) as start_job 
    from 
    logs l 
    join users u on l.user_id = u.user_id 
    where 
    l.timepoint between from_date and thru_date 
    group by 
    l.user_id, u.username 
$BODY$ 
    LANGUAGE sql VOLATILE 
    COST 100 
    ROWS 1000; 

然後你的查詢是:

select * from get_stats('2015-01-01', '2015-05-31') 

就個人而言,我會跳過功能,只是將其創建爲一個查詢,但也有原因,你會這是可以想象的想要功能包裝。

- 編輯 - 基於企圖編輯

,我看你會不會介意的查詢。此外,你想要沒有條目的用戶。

與所有的考慮到這一點,我想這可能工作:

select 
    u.user_id, u.username, 
    sum (case when action = 'create_quote' then 1 else 0 end) as create_quote, 
    sum (case when action = 'send_quote' then 1 else 0 end) as send_quote, 
    sum (case when action = 'start_job' then 1 else 0 end) as start_job 
    from 
    users u 
    left join logs l on 
     l.user_id = u.user_id and 
     l.timepoint between '2015-01-01' and '2015-05-31' 
    group by 
    u.user_id, u.username 
+0

小修正,然後它應如下工作:「由 l.user_id組成的用戶名,」u.username「必須是」由 u.user_id組成的用戶名,u.username「。你也可能想改變標題,使其適合cte和遞歸嗎? – Sebastian

+0

是的,你是對的 - 這是固定的。至於標題,這是你的問題,所以改變! – Hambone