65

返す PostgreSQL クエリを作成する必要があります

  • 一日
  • その日に見つかったオブジェクトの数

その日にオブジェクトが見つからなかったとしても、毎日が結果に表示されることが重要です。(これは以前に議論されましたが、私は特定のケースで物事を機能させることができませんでした.)

最初に、結合できる日の範囲を生成する SQL クエリを見つけました。

SELECT to_char(date_trunc('day', (current_date - offs)), 'YYYY-MM-DD')
AS date 
FROM generate_series(0, 365, 1) 
AS offs

結果:

    date    
------------
 2013-03-28
 2013-03-27
 2013-03-26
 2013-03-25
 ...
 2012-03-28
(366 rows)

今、私はそれを「作成された」列を持つ「sharer_emailshare」という名前のテーブルに結合しようとしています:

Table 'public.sharer_emailshare'
column    |   type  
-------------------
id        | integer
created   | timestamp with time zone
message   | text
to        | character varying(75)

これが私がこれまでに持っている最高のGROUP BYクエリです:

SELECT d.date, count(se.id) FROM (
    select to_char(date_trunc('day', (current_date - offs)), 'YYYY-MM-DD')
    AS date 
    FROM generate_series(0, 365, 1) 
    AS offs
    ) d 
JOIN sharer_emailshare se 
ON (d.date=to_char(date_trunc('day', se.created), 'YYYY-MM-DD'))  
GROUP BY d.date;

結果:

    date    | count 
------------+-------
 2013-03-27 |    11
 2013-03-24 |     2
 2013-02-14 |     2
(3 rows)

望ましい結果:

    date    | count 
------------+-------
 2013-03-28 |     0
 2013-03-27 |    11
 2013-03-26 |     0
 2013-03-25 |     0
 2013-03-24 |     2
 2013-03-23 |     0
 ...
 2012-03-28 |     0
(366 rows)

私が正しく理解していれば、これは私がプレーン (暗黙のINNER)を使用しているためであり、postgres docs で説明されているようにJOIN、これは予想される動作です。

私は数十の StackOverflow ソリューションを調べましたが、クエリが機能するものはすべて MySQL/Oracle/MSSQL に固有のもののようで、それらを PostgreSQL に変換するのに苦労しています。

この質問をした人は、Postgres で答えを見つけましたが、しばらく前に有効期限が切れたペーストビン リンクに置きました。

, , ,に切り替えたりLEFT OUTER JOIN、 null の場合はステートメントを使用して別の値をサブにしたり、デフォルト値を提供したりしようとしましたが、必要なものを取得する方法でそれらを使用できませんでした。RIGHT JOINRIGHT OUTER JOINCROSS JOINCASECOALESCE

どんな支援も大歓迎です!そして、すぐにその巨大な PostgreSQL の本を読み始めることを約束します ;)

4

5 に答える 5

58

left outer join内部結合の代わりに必要なのは次のとおりです。

SELECT d.date, count(se.id)
FROM (SELECT to_char(date_trunc('day', (current_date - offs)), 'YYYY-MM-DD') AS date 
      FROM generate_series(0, 365, 1) AS offs
     ) d LEFT OUTER JOIN
     sharer_emailshare se 
     ON d.date = to_char(date_trunc('day', se.created), 'YYYY-MM-DD'))  
GROUP BY d.date;
于 2013-03-28T20:06:09.690 に答える
38

Gordon Linoff の役立つ回答を拡張して、次のようないくつかの改善を提案します。

  • ::dateの代わりに使用date_trunc('day', ...)
  • 文字型ではなく日付型で結合します (よりクリーンです)。
  • 後で簡単に変更できるように、特定の日付範囲を使用します。この場合、テーブルの最新のエントリの 1 年前を選択します。これは、他のクエリでは簡単には実行できませんでした。
  • 任意のサブクエリの合計を計算します (CTE を使用)。対象の列を日付型にキャストして、date_column と呼ぶだけです。
  • 累積合計の列を含めます。(なぜだめですか?)

これが私のクエリです:

WITH dates_table AS (
    SELECT created::date AS date_column FROM sharer_emailshare WHERE showroom_id=5
)
SELECT series_table.date, COUNT(dates_table.date_column), SUM(COUNT(dates_table.date_column)) OVER (ORDER BY series_table.date) FROM (
    SELECT (last_date - b.offs) AS date
        FROM (
            SELECT GENERATE_SERIES(0, last_date - first_date, 1) AS offs, last_date from (
                 SELECT MAX(date_column) AS last_date, (MAX(date_column) - '1 year'::interval)::date AS first_date FROM dates_table
            ) AS a
        ) AS b
) AS series_table
LEFT OUTER JOIN dates_table
    ON (series_table.date = dates_table.date_column)
GROUP BY series_table.date
ORDER BY series_table.date

クエリをテストしたところ、同じ結果に加えて、累積合計の列が生成されました。

于 2014-03-14T02:16:34.620 に答える
7

ゴードン・リノフの回答に基づいてWHERE、元の質問で言及しなかった条項があるという別の問題があることに気付きました。

ネイキッドの代わりにWHERE、サブクエリを作成しました。

SELECT d.date, count(se.id) FROM (
    select to_char(date_trunc('day', (current_date - offs)), 'YYYY-MM-DD')
    AS date 
    FROM generate_series(0, 365, 1) 
    AS offs
    ) d 
LEFT OUTER JOIN (
    SELECT * FROM sharer_emailshare 
    WHERE showroom_id=5
) se
ON (d.date=to_char(date_trunc('day', se.created), 'YYYY-MM-DD')) 
GROUP BY d.date;
于 2013-03-28T22:20:03.450 に答える