2016-09-18 84 views
1

我要顯示一個日期範圍(統計)喜歡的:使用外生在Postgres的generate_series並檢索空值設爲「0」

Dates  | Count 
-------------------- 
"2016-09-01" | 0 
"2016-09-02" | 0 
"2016-09-03" | 0 
"2016-09-04" | 0 
"2016-09-05" | 0 
"2016-09-06" | 12 
"2016-09-07" | 9 
"2016-09-08" | 0 
"2016-09-09" | 90 

原始SQL查詢:

select date(d) as day, count(clicks.id) 
    from generate_series(
    current_date - interval '13 day', 
    current_date, 
    '1 day' 
) d 
left join clicks on date(clicks.inserted_at) = d and clicks.link_id = 15 
group by day order by day; 

我很想與外生使用它沒有我找到了原始SQL

最接近的事是:

query = from c in Like 
    where: c.link_id == ^link.id 

... 

from(c in query, 
    join: day in fragment("select generate_series(current_date - interval '10 day', current_date, '1 day')::date AS d "), 
    on: fragment("date(?) = d", field(c, :inserted_at)), 
    group_by: fragment("day"), 
    order_by: fragment("day"), 
    select: %{ 
    day: fragment("date(d) as day"), 
    count: count(c.id) 
    } 
) 

但它只返回表格中的日期而不是整個範圍(即;對於沒有像那天

回答

4

您可以使用right_join因爲你的外生查詢與clicks加入clicks與產生的日期,而不是生成的日期就像你在原始SQL確實日期)顯示0 。

測試:

alias MyApp.{Click, Repo} 
import Ecto.Query 

from(c in Click, 
    order_by: c.inserted_at, 
    select: fragment("date(?) as day", c.inserted_at) 
) 
|> Repo.all 
|> IO.inspect 

from(c in Click, 
    right_join: day in fragment("select generate_series(current_date - interval '10 day', current_date, '1 day')::date AS d "), 
    on: fragment("date(?) = d", field(c, :inserted_at)), 
    group_by: fragment("day"), 
    order_by: fragment("day"), 
    select: %{ 
    day: fragment("date(d) as day"), 
    count: count(c.id) 
    } 
) 
|> Repo.all 
|> IO.inspect 

輸出:

[debug] QUERY OK source="clicks" db=1.9ms 
SELECT date(c0."inserted_at") as day FROM "clicks" AS c0 ORDER BY c0."inserted_at" [] 
[{2016, 9, 12}, {2016, 9, 13}, {2016, 9, 13}, {2016, 9, 13}, {2016, 9, 13}, 
{2016, 9, 15}, {2016, 9, 17}, {2016, 9, 17}] 
[debug] QUERY OK source="clicks" db=1.8ms 
SELECT date(d) as day, count(c0."id") FROM "clicks" AS c0 RIGHT OUTER JOIN (select generate_series(current_date - interval '10 day', current_date, '1 day')::date AS d) AS f1 ON date(c0."inserted_at") = d GROUP BY day ORDER BY day [] 
[%{count: 0, day: {2016, 9, 8}}, %{count: 0, day: {2016, 9, 9}}, 
%{count: 0, day: {2016, 9, 10}}, %{count: 0, day: {2016, 9, 11}}, 
%{count: 1, day: {2016, 9, 12}}, %{count: 4, day: {2016, 9, 13}}, 
%{count: 0, day: {2016, 9, 14}}, %{count: 1, day: {2016, 9, 15}}, 
%{count: 0, day: {2016, 9, 16}}, %{count: 2, day: {2016, 9, 17}}, 
%{count: 0, day: {2016, 9, 18}}] 

編輯:您可能還需要更多地利用外生強大的查詢能力,並減少依賴asfragment。下面的查詢生成相同的輸出:

from(c in Click, 
    right_join: day in fragment("select generate_series(current_date - interval '10 day', current_date, '1 day')::date AS d"), 
    on: day.d == fragment("date(?)", c.inserted_at), 
    group_by: day.d, 
    order_by: day.d, 
    select: %{ 
    day: fragment("date(?)", day.d), 
    count: count(c.id) 
    } 
) 
+0

哦謝謝@Dogbert非常爲您的解決方案,它的偉大工程,並解釋:) – kayne

+0

謝謝你這麼多的輝煌! – pip