PostgreSQL
 sql >> Cơ Sở Dữ Liệu >  >> RDS >> PostgreSQL

Chọn tổng và số dư đang hoạt động trong 18 tháng qua với create_series

Giải pháp cơ bản

Tạo danh sách đầy đủ các tháng và LEFT JOIN phần còn lại cho nó:

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

Các câu trả lời liên quan có giải thích thêm:

Giải pháp nâng cao cho trường hợp của bạn

Truy vấn của bạn phức tạp hơn tôi hiểu lần đầu. Bạn cần số tiền đang chạy trên tất cả các hàng của mục đã chọn, sau đó bạn muốn cắt các hàng cũ hơn một ngày tối thiểu và điền vào các tháng còn thiếu bằng tổng được tính trước của tháng trước.

Tôi đạt được điều này ngay bây giờ với 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 với một trường hợp thử nghiệm tối thiểu.

Những điểm chính:

  • Tôi đã xóa hoàn toàn CHẾ ĐỘ XEM của bạn khỏi truy vấn. Nhiều chi phí mà không đạt được.

  • Vì bạn chọn một đơn item_id , bạn không cần phải GROUP BY item_id hoặc PARTITION BY item_id .

  • Sử dụng bí danh bảng ngắn gọn và làm rõ ràng tất cả các tham chiếu - đặc biệt là khi đăng trên diễn đàn công khai.

  • Dấu ngoặc đơn trong các phép nối của bạn chỉ là tiếng ồn. Các phép nối vẫn được thực thi từ trái sang phải theo mặc định.

  • Giới hạn ngày được đơn giản hóa (vì tôi hoạt động với dấu thời gian):

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

    tương đương, nhưng đơn giản và nhanh hơn:

    current_date - date_part('day',current_date)::integer - 540
    current_date - date_part('day',current_date)::integer
  • Bây giờ tôi điền vào các tháng còn thiếu sau tất cả các phép tính với generate_series() cuộc gọi trên mỗi hàng.

  • Nó phải là LEFT JOIN LATERAL ... ON TRUE , không phải dạng rút gọn của JOIN LATERAL để bắt trường hợp góc của hàng cuối cùng. Giải thích chi tiết:

Ghi chú quan trọng bên lề:

character(22) là một khủng khiếp kiểu dữ liệu cho khóa chính (hoặc bất kỳ cột). Chi tiết:

Tốt nhất đây sẽ là một int hoặc bigint hoặc có thể là UUID .

Ngoài ra, lưu trữ số tiền dưới dạng money nhập hoặc integer (đại diện cho Cents) nói chung hoạt động tốt hơn nhiều.

Về lâu dài , hiệu suất chắc chắn sẽ giảm đi, vì bạn phải bao gồm tất cả các hàng ngay từ đầu trong tính toán của mình. Bạn nên cắt bỏ các hàng cũ và hiện thực hóa số dư của on_hold trên cơ sở hàng năm hoặc một cái gì đó.




  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. so sánh các chuỗi trong PostgreSQL

  2. Cách tìm kiếm nếu toàn bộ từ tồn tại trong một chuỗi trong Postgres

  3. Cách trừ giây cho ngày giờ của postgres

  4. Chặn CHỌN cho đến khi có kết quả

  5. Nhận các đối tượng của các đối tượng trong một truy vấn trong đường ray