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

generate_seriesを使用して過去18か月の合計とランニングバランスを選択する

    基本的な解決策

    月の完全なリストを生成し、LEFT JOIN 残りの部分:

    SELECT *
    FROM  (
       SELECT to_char(m, 'YYYY-MON') AS yyyymmm
       FROM   generate_series(<start_date>, <end_date>, interval '1 month') m
       ) m
    LEFT  JOIN ( <your query here> ) q USING (yyyymmm);
    

    詳細な説明付きの関連回答:

    ケースの高度なソリューション

    あなたの質問は私が最初に理解したよりも複雑です。 すべての現在の合計が必要です 選択したアイテムの行の場合、最小日付より古い行をトリミングし、不足している月に前月の事前計算された合計を入力します。

    私は今、LEFT JOIN LATERALでこれを達成しています 。

    SELECT COALESCE(m.yearmonth, c.yearmonth)::date, sold_qty, on_hand
    FROM  (
       SELECT yearmonth
            , COALESCE(sold_qty, 0) AS sold_qty
            , sum(on_hand_mon) OVER (ORDER BY yearmonth) AS on_hand
            , lead(yearmonth)  OVER (ORDER BY yearmonth)
                                    - interval '1 month' AS nextmonth
       FROM (
          SELECT date_trunc('month', c.change_date) AS yearmonth
               , sum(c.sold_qty / s.qty)::numeric(18,2) AS sold_qty
               , sum(c.on_hand) AS on_hand_mon
          FROM   item_change      c         
          LEFT   JOIN item        i USING (item_id)
          LEFT   JOIN item_size   s ON s.item_id = i.item_id AND s.name = i.sell_size
          LEFT   JOIN item_plu    p ON p.item_id = i.item_id AND p.seq_num = 0
          WHERE  c.change_date < date_trunc('month', now()) - interval '1 day'
          AND    c.item_id = (SELECT item_id FROM item_plu WHERE number = '51515')
          GROUP  BY 1
          ) sub
       ) c
    LEFT   JOIN LATERAL generate_series(c.yearmonth
                                      , c.nextmonth
                                      , interval '1 month') m(yearmonth) ON TRUE
    WHERE  c.yearmonth > date_trunc('year', now()) - interval '540 days'
    ORDER  BY COALESCE(m.yearmonth, c.yearmonth);
    

    SQLフィドル 最小限のテストケースで。

    主なポイント:

    • クエリからVIEWを完全に削除しました。利益がないために多くの費用がかかります。

    • シングルを選択したため item_idGROUP BY item_idを実行する必要はありません またはPARTITION BY item_id

    • 短いテーブルエイリアスを使用し、すべての参照を明確にします。特に、公開フォーラムに投稿する場合はそうです。

    • 結合の括弧は単なるノイズでした。結合は、デフォルトで左から右に実行されます。

    • 簡略化された日付境界(タイムスタンプで操作するため):

      date_trunc('year', current_date)  - interval '540 days'
      date_trunc('month', current_date) - interval '1 day'
      

      同等ですが、以下よりも単純で高速です:

      current_date - date_part('day',current_date)::integer - 540
      current_date - date_part('day',current_date)::integer
    • すべての計算の後に不足している月をgenerate_series()で埋めるようになりました 行ごとの呼び出し。

    • LEFT JOIN LATERAL ... ON TRUEである必要があります 、JOIN LATERALの短縮形ではありません 最後の列のコーナーケースをキャッチします。詳細な説明:

    重要な注意事項:

    character(22) ひどい 主キー(または任意)のデータ型 桁)。詳細:

    理想的には、これはintになります またはbigint 列、または場合によっては UUID

    また、金額をmoney タイプまたはinteger (セントを表す)全体的にはるかに優れたパフォーマンスを発揮します。

    長期的には 、計算の最初からすべての行を含める必要があるため、パフォーマンスは低下する可能性があります。古い行を切り取り、on_holdのバランスを具体化する必要があります 毎年か何かで。




    1. 誤ったGUIDの順序

    2. PostgresSQLのORDERBYでLENGTH(計算列)を使用する

    3. シリアライズ可能な分離を使用したPostgreSQL9.2.1での述語ロック

    4. MySQLからほとんど重複するレコードを選択的に削除します