АКТУАЛИЗИРАНЕ
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