PostgreSQL
 sql >> Teknologi Basis Data >  >> RDS >> PostgreSQL

Memilih jumlah dan saldo berjalan selama 18 bulan terakhir dengan generate_series

Solusi dasar

Buat daftar lengkap bulan dan LEFT JOIN sisanya:

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);

Jawaban terkait dengan penjelasan lebih lanjut:

Solusi lanjutan untuk kasus Anda

Permintaan Anda lebih rumit daripada yang pertama kali saya pahami. Anda membutuhkan jumlah berjalan di atas semua baris item yang dipilih, lalu Anda ingin memangkas baris yang lebih lama dari tanggal minimum, dan mengisi bulan yang hilang dengan jumlah yang telah dihitung sebelumnya dari bulan sebelumnya.

Saya mencapai ini sekarang dengan 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 Fiddle dengan kasus uji minimum.

Poin utama:

  • Saya menghapus VIEW Anda dari kueri sepenuhnya. Banyak biaya tanpa keuntungan.

  • Karena Anda memilih tunggal item_id , Anda tidak perlu GROUP BY item_id atau PARTITION BY item_id .

  • Gunakan alias tabel pendek dan buat semua referensi tidak ambigu - terutama saat memposting di forum publik.

  • Tanda kurung di gabungan Anda hanyalah kebisingan. Gabungan tetap dijalankan dari kiri ke kanan secara default.

  • Batas tanggal yang disederhanakan (karena saya beroperasi dengan cap waktu):

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

    setara, tetapi lebih sederhana &lebih cepat dari:

    current_date - date_part('day',current_date)::integer - 540
    current_date - date_part('day',current_date)::integer
  • Saya sekarang mengisi bulan yang hilang setelah semua perhitungan dengan generate_series() panggilan per baris.

  • Harus LEFT JOIN LATERAL ... ON TRUE , bukan bentuk pendek dari JOIN LATERAL untuk menangkap kasus sudut dari baris terakhir. Penjelasan detail:

Catatan sampingan penting:

character(22) adalah mengerikan tipe data untuk kunci utama (atau apa saja kolom). Detail:

Idealnya ini adalah int atau bigint kolom, atau mungkin UUID .

Juga, menyimpan jumlah uang sebagai money ketik atau integer (mewakili Cents) berkinerja jauh lebih baik secara keseluruhan.

Dalam jangka panjang , kinerjanya pasti akan menurun, karena Anda harus memasukkan semua baris sejak awal dalam perhitungan Anda. Anda harus memotong baris lama dan mewujudkan keseimbangan on_hold setiap tahun atau semacamnya.




  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Cara mengisi baris berdasarkan data jenis acara

  2. Di psql, mengapa beberapa perintah tidak berpengaruh?

  3. PostgisDialect vs PostgreSQLDialect atau keduanya?

  4. BUAT INDEKS UNIK JIKA TIDAK ADA di postgreSQL

  5. Bagaimana Anda menggunakan variabel dalam skrip PostgreSQL sederhana?