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

Кумулативна сума за набор от редове в mysql

АКТУАЛИЗИРАНЕ

MySQL 8.0 въвежда "прозоречни функции", функционалност, еквивалентна на "прозоречни функции" на SQL Server (с разделяне и подреждане, предоставени от Transact-SQL OVER синтаксис) и Oracle „аналитични функции“.

Справочно ръководство за MySQL 12.21 Функции на прозореца https://dev.mysql .com/doc/refman/8.0/en/window-functions.html

Отговорът, предоставен тук, е подход за MySQL версии преди 8.0.

ОРИГИНАЛЕН ОТГОВОР

MySQL не предоставя функцията за анализ на типа, която бихте използвали, за да получите текуща "кумулативна сума", като аналитичните функции, налични в други СУБД (като Oracle или SQL Server.)

Но е възможно да се емулират някои аналитични функции, като се използва MySQL.

Има (поне) два работещи подхода:

Едната е да използвате корелирана подзаявка, за да получите междинната сума. Този подход може да бъде скъп за големи набори и сложен, ако предикатите на външната заявка са сложни. Наистина зависи от това колко сложно е това "множество обединявания на множество таблици". (За съжаление, MySQL също не поддържа CTE.)

Другият подход е да се използват потребителски променливи на MySQL, за да се направи някаква обработка на прекъсване на контрола. "Тръкът" тук е резултатите от вашата заявка да бъдат сортирани (с помощта на ORDER BY) и след това да се обвие вашата заявка в друга заявка.

Ще дам пример за последния подход.

Поради реда, в който MySQL изпълнява операциите, cumulative_total колоната трябва да бъде изчислена преди стойността от id и day от текущия ред се записват в потребителски променливи. Най-лесно е да поставите тази колона на първо място.

Вграденият изглед с псевдоним като i (в заявката по-долу) е там, за да инициализира потребителските променливи, само в случай, че те вече са зададени в сесията. Ако те вече имат присвоени стойности, искаме да игнорираме текущите им стойности и най-лесният начин да направим това е да ги инициализираме.

Оригиналната ви заявка се обвива в скоби и й се дава псевдоним, c в примера по-долу. Единствената промяна в оригиналната ви заявка е добавянето на клауза ORDER BY, така че можем да сме сигурни, че обработваме редовете от заявката последователно.

Външният избор проверява дали id и day стойност от текущия ред "съвпада" с предишния ред. Ако го направят, добавяме amount от текущия ред до кумулативната междинна сума. Ако те не съвпадат, тогава нулираме кумулативната междинна сума на нула и добавяме сумата от текущия ред (или, по-просто, просто присвояваме сумата от текущия ред).

След като направим изчисляването на кумулативната сума, запазваме id и day стойности от текущия ред в потребителски променливи, така че да са налични, когато обработим следващия ред.

Например:

SELECT IF(@prev_id = c.id AND @prev_day = c.day
         ,@cumtotal := @cumtotal + c.amount
         ,@cumtotal := c.amount) AS cumulative_total
     , @prev_id  := c.id  AS `id`
     , @prev_day := c.day AS `day`
     , c.hr
     , c.amount AS `amount'
  FROM ( SELECT @prev_id  := NULL
              , @prev_day := NULL
              , @subtotal := 0
       ) i
  JOIN (

         select id, day, hr, amount from
         ( //multiple joins on multiple tables)a
         left join
         (//unions on multiple tables)b
         on a.id=b.id

         ORDER BY 1,2,3
       ) c

Ако е необходимо да се върнат колоните в различен ред, с кумулативен сбор като последна колона, тогава една от опциите е да обвиете целия израз в набор от скоби и да използвате тази заявка като вграден изглед:

SELECT d.id
     , d.day
     , d.hr
     , d.amount
     , d.cumulative_total
FROM (
       // query from above
     ) d


  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. TIMEDIFF() срещу SUBTIME() в MySQL:Каква е разликата?

  2. Деактивирайте ONLY_FULL_GROUP_BY

  3. Базата данни не се актуализира автоматично с MySQL и Python

  4. Как да върнете позицията на аргумент в списък с аргументи в MySQL

  5. Нулирайте Root паролата на MySQL Server