Обчислення сукупної суми в PostgreSQL


85

Я хочу знайти сукупну або поточну кількість поля та вставити його з індексів у таблицю. Моя інсценізаційна структура приблизно така:

ea_month    id       amount    ea_year    circle_id
April       92570    1000      2014        1
April       92571    3000      2014        2
April       92572    2000      2014        3
March       92573    3000      2014        1
March       92574    2500      2014        2
March       92575    3750      2014        3
February    92576    2000      2014        1
February    92577    2500      2014        2
February    92578    1450      2014        3          

Я хочу, щоб моя цільова таблиця виглядала приблизно так:

ea_month    id       amount    ea_year    circle_id    cum_amt
February    92576    1000      2014        1           1000 
March       92573    3000      2014        1           4000
April       92570    2000      2014        1           6000
February    92577    3000      2014        2           3000
March       92574    2500      2014        2           5500
April       92571    3750      2014        2           9250
February    92578    2000      2014        3           2000
March       92575    2500      2014        3           4500
April       92572    1450      2014        3           5950

Я справді дуже заплутаний у тому, як піти на досягнення цього результату. Я хочу досягти цього результату за допомогою PostgreSQL.

Хто-небудь може підказати, як дійти до досягнення цього набору результатів?


1
Як отримати cum_amount 1000 у вашій цільовій таблиці? Для circle_id сума здається 2000.

Відповіді:


130

В основному, вам потрібна функція вікна . Сьогодні це стандартна функція. На додаток до справжніх функцій вікна, ви можете використовувати будь-яку сукупну функцію як функцію вікна в Postgres, додавши OVERречення.

Особлива складність тут полягає в отриманні розділів та порядку сортування:

SELECT ea_month, id, amount, ea_year, circle_id
     , sum(amount) OVER (PARTITION BY circle_id
                         ORDER BY ea_year, ea_month) AS cum_amt
FROM   tbl
ORDER  BY circle_id, month;

І ні GROUP BY .

Сума для кожного рядка обчислюється від першого рядка до розділу до поточного рядка - або, якщо бути точним, цитуючи посібник :

Параметр обрамлення за замовчуванням - RANGE UNBOUNDED PRECEDINGце те саме, що RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW. З ORDER BY, це встановлює рамки , щоб бути все рядки з розділу запуску через останні в поточному рядку ORDER BYоднолітків .

... що є сукупною або поточною сумою, яку ви шукаєте. Сміливий наголос мій.

Рядки з тим самим (circle_id, ea_year, ea_month)є "однолітками" у цьому запиті. Усі вони показують однакову поточну суму з усіма однолітками, доданими до суми. Але я припускаю , що ваш стіл UNIQUEна (circle_id, ea_year, ea_month), то порядок сортування є детермінованим і ні одна рядок не має однолітків.

Тепер ORDER BY ... ea_month не буде працювати зі рядками для назв місяців . Postgres буде сортувати в алфавітному порядку відповідно до налаштування мови.

Якщо dateу вашій таблиці зберігаються фактичні значення, ви можете правильно сортувати. Якщо ні, я пропоную замінити ea_yearі ea_monthна один стовпець monтипу dateу вашій таблиці.

  • Перетворіть те, що у вас є to_date():

      to_date(ea_year || ea_month , 'YYYYMonth') AS mon
    
  • Для відображення ви можете отримати оригінальні рядки за допомогою to_char():

      to_char(mon, 'Month') AS ea_month
      to_char(mon, 'YYYY') AS ea_year
    

Не зважаючи на невдалий дизайн, це спрацює:

SELECT ea_month, id, amount, ea_year, circle_id
     , sum(amount) OVER (PARTITION BY circle_id ORDER BY mon) AS cum_amt
FROM   (SELECT *, to_date(ea_year || ea_month, 'YYYYMonth') AS mon FROM tbl)
ORDER  BY circle_id, mon;

Дякую за рішення .. Чи можете ви допомогти мені ще з одним? Я хочу реалізувати те саме, використовуючи курсор, логіка полягає в тому, що кожне коло матиме лише один запис протягом місяця року. І функція повинна працювати раз на місяць. Як я можу цього досягти?
Юсуф Султан,

4
@YousufSultan: Здебільшого є краще рішення, ніж курсор. Це точно для нового питання. Почніть нове запитання.
Ервін Брандштеттер

Я знаходжу цю відповідь неповним без хоча б відзначити , що є «обрамлення» тут відбувається , який по замовчуванням range unbounded preceding, який є таким же , як range between unbounded preceding and current row. Ось чому sum()при використанні як віконна функція створює загальний результат - тоді як інші віконні функції не мають цього типового кадру.
Колін 'Харт

1
@ Colin'tHart: Я додав ще кілька для уточнення.
Ервін Брандштеттер

Ось посилання на подібне запитання з більш простим запитом ( PARTITIONце не завжди потрібно для створення загальної суми): stackoverflow.com/a/5700744/175830
Джейсон Аксельсон,
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.