ATUALIZAÇÃO
O MySQL 8.0 introduz "funções de janela", funcionalidade equivalente às "funções de janela" do SQL Server (com particionamento e ordenação fornecidos pelo Transact-SQL
OVER
sintaxe) e "funções analíticas" do Oracle. Manual de referência do MySQL 12.21 Funções de janela https://dev.mysql .com/doc/refman/8.0/en/window-functions.html
A resposta fornecida aqui é uma abordagem para versões do MySQL anteriores a 8.0.
RESPOSTA ORIGINAL
O MySQL não fornece a função analítica de tipo que você usaria para obter uma "soma cumulativa" em execução, como as funções analíticas disponíveis em outros DBMS (como Oracle ou SQL Server).
Mas, é possível emular algumas funções analíticas, usando o MySQL.
Existem (pelo menos) duas abordagens viáveis:
Uma é usar uma subconsulta correlacionada para obter o subtotal. Essa abordagem pode ser cara em conjuntos grandes e complicada se os predicados na consulta externa forem complicados. Realmente depende de quão complicado é "várias junções em várias tabelas". (Infelizmente, o MySQL também não suporta CTEs.)
A outra abordagem é fazer uso de variáveis de usuário do MySQL, para fazer algum processamento de quebra de controle. O "truque" aqui é classificar os resultados da sua consulta (usando um ORDER BY) e, em seguida, envolver sua consulta em outra consulta.
Vou dar um exemplo da última abordagem.
Devido à ordem em que o MySQL executa as operações, o
cumulative_total
coluna precisa ser computada antes do valor de id
e day
da linha atual são salvos em variáveis de usuário. É mais fácil colocar esta coluna primeiro. A visualização inline com o alias de i (na consulta abaixo) serve apenas para inicializar as variáveis do usuário, caso elas já estejam definidas na sessão. Se eles já tiverem valores atribuídos, queremos ignorar seus valores atuais e a maneira mais fácil de fazer isso é inicializá-los.
Sua consulta original é colocada entre parênteses e recebe um alias,
c
no exemplo abaixo. A única alteração em sua consulta original é a adição de uma cláusula ORDER BY, para que possamos ter certeza de que processamos as linhas da consulta em sequência. A seleção externa verifica se o
id
e day
valor da linha atual "corresponde" à linha anterior. Se sim, adicionamos o amount
da linha atual para o subtotal cumulativo. Se eles não corresponderem, redefinimos o subtotal cumulativo para zero e adicionamos o valor da linha atual (ou, mais simplesmente, atribuímos o valor da linha atual). Após termos feito o cálculo do total cumulativo, salvamos o
id
e day
valores da linha atual em variáveis de usuário, para que estejam disponíveis quando processarmos a próxima linha. Por exemplo:
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
Se for necessário retornar as colunas em uma ordem diferente, com o total cumulativo como a última coluna, uma opção é envolver toda essa instrução em um conjunto de parênteses e usar essa consulta como uma visualização em linha:
SELECT d.id
, d.day
, d.hr
, d.amount
, d.cumulative_total
FROM (
// query from above
) d