PostgreSQL
 sql >> база данни >  >> RDS >> PostgreSQL

Избиране на сума и текущо салдо за последните 18 месеца с generate_series

Основно решение

Генерирайте пълен списък с месеци и 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 Fiddle с минимален тестов случай.

Основни точки:

  • Премахнах напълно вашия VIEW от заявката. Много разходи за никаква печалба.

  • Тъй като избирате сингъл item_id , не е необходимо да GROUP 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. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Тези символи валидни ли са за XML?

  2. Намерете изречения с две съседни думи в стр

  3. Проверете дали ключът съществува в JSON с PL/pgSQL?

  4. Премахнете всички функции от базата данни на Postgres

  5. Преглед на кеширането за PostgreSQL