sql >> データベース >  >> RDS >> PostgreSQL

日付範囲で区切られた行数のクエリ

    crosstab() 2つのパラメータを持つ関数。

    2012年の値を取得するには、次のように機能する必要があります:

    SELECT * FROM crosstab(
         $$SELECT testname, to_char(last_update, 'mon_YYYY'), count(*)::int AS ct
            FROM   tests
            WHERE  current_status = 'FAILED'
            AND    last_update >= '2012-01-01 0:0'
            AND    last_update <  '2013-01-01 0:0'  -- proper date range!
            GROUP  BY 1,2
            ORDER  BY 1,2$$
    
        ,$$VALUES
          ('jan_2012'::text), ('feb_2012'), ('mar_2012')
        , ('apr_2012'), ('may_2012'), ('jun_2012')
        , ('jul_2012'), ('aug_2012'), ('sep_2012')
        , ('oct_2012'), ('nov_2012'), ('dec_2012')$$)
    AS ct (testname  text
       , jan_2012 int, feb_2012 int, mar_2012 int
       , apr_2012 int, may_2012 int, jun_2012 int
       , jul_2012 int, aug_2012 int, sep_2012 int
       , oct_2012 int, nov_2012 int, dec_2012 int);
    

    この関連する質問で詳細な説明を見つけてください。

    テストしませんでした。 @Craigがコメントしたように、サンプル値が役に立ちました。
    今すぐ自分のテストケースでテストしました。

    NULL値を表示しない

    主な問題(行のない月はまったく表示されない)は、crosstab()によって回避されます。 2つのパラメータを持つ関数。

    COALESCEは使用できません NULLであるため、内部クエリで 値はcrosstab()によって挿入されます 自体。あなたは...

    1。すべてをサブクエリにラップします:

    SELECT testname
          ,COALESCE(jan_2012, 0) AS jan_2012
          ,COALESCE(feb_2012, 0) AS feb_2012
          ,COALESCE(mar_2012, 0) AS mar_2012
          , ...
    FROM (
        -- query from above)
        ) x;
    

    2。 LEFT JOIN 月の完全なリストへの主要なクエリ。

    この場合、定義上、2番目のパラメーターは必要ありません。
    より広い範囲の場合は、generate_series()を使用できます。 値を作成します。

    SELECT * FROM crosstab(
         $$SELECT t.testname, m.mon, count(x.testname)::int AS ct
           FROM  (
              VALUES
               ('jan_2012'::text), ('feb_2012'), ('mar_2012')
              ,('apr_2012'), ('may_2012'), ('jun_2012')
              ,('jul_2012'), ('aug_2012'), ('sep_2012')
              ,('oct_2012'), ('nov_2012'), ('dec_2012')
           ) m(mon)
           CROSS JOIN (SELECT DISTINCT testname FROM tests) t
           LEFT JOIN (
              SELECT testname
                    ,to_char(last_update, 'mon_YYYY') AS mon
              FROM   tests
              WHERE  current_status = 'FAILED'
              AND    last_update >= '2012-01-01 0:0'
              AND    last_update <  '2013-01-01 0:0'  -- proper date range!
              ) x USING (mon)
           GROUP  BY 1,2
           ORDER  BY 1,2$$
         )
    AS ct (testname  text
       , jan_2012 int, feb_2012 int, mar_2012 int
       , apr_2012 int, may_2012 int, jun_2012 int
       , jul_2012 int, aug_2012 int, sep_2012 int
       , oct_2012 int, nov_2012 int, dec_2012 int);
    

    サンプルデータを含むテストケース

    これは、OPが提供できなかったいくつかのサンプルデータを含むテストケースです。これを使用してテストし、機能させました。

    CREATE TEMP TABLE tests (
      id             bigserial PRIMARY KEY
     ,testname       text NOT NULL
     ,last_update    timestamp without time zone NOT NULL DEFAULT now()
     ,current_status text NOT NULL
     );
    
    INSERT INTO tests (testname, last_update, current_status)
    VALUES
      ('foo', '2012-12-05 21:01', 'FAILED')
     ,('foo', '2012-12-05 21:01', 'FAILED')
     ,('foo', '2012-11-05 21:01', 'FAILED')
     ,('bar', '2012-02-05 21:01', 'FAILED')
     ,('bar', '2012-02-05 21:01', 'FAILED')
     ,('bar', '2012-03-05 21:01', 'FAILED')
     ,('bar', '2012-04-05 21:01', 'FAILED')
     ,('bar', '2012-05-05 21:01', 'FAILED');
    



    1. 動的クエリを使用してテーブル変数に挿入するにはどうすればよいですか?

    2. 一般的なSQLiteの問題を解決するのに役立つ方法はありますか?

    3. これが重複していないか確認してください

    4. 内部結合2つのテーブル、varcharフィールドを集約