Primeiro construa a soma, depois junte-se. Assim:
SELECT i.uid
,i.date
,i.v_in
,COALESCE(o.v_out, 0) AS v_out
,(i.v_in - COALESCE(o.v_out, 0)) AS balance
FROM (
SELECT date
,uid
,SUM(value_in) AS v_in
FROM table1
GROUP BY 1,2
) i
LEFT JOIN (
SELECT date
,uid
,SUM(value_out) AS v_out
FROM table2
GROUP BY 1,2
) o USING (date, uid)
Do jeito que você tinha, cada
value_in
seria combinado com cada value_out
correspondente , multiplicando assim os números. Você deve agregar primeiro e depois participar de um soma com um out-sum e tudo é groovy. Ou é? O que acontece se não houver
value_in
ou value_out
para um determinado (date, uid)
? Ou apenas value_in
Ou apenas value_out
? Sua consulta falhará. Melhorei usando um
LEFT JOIN
em vez de [INNER] JOIN
, mas o que você realmente quer é um FULL OUTER JOIN
- um dos recursos ausentes no MySQL. Você pode fornecer uma lista de dias em uma tabela separada e
LEFT JOIN
ambas as tabelas, ou você pode contornar o recurso ausente com duas vezes LEFT JOIN
e UNION
. Veja aqui por exemplo
. Ou você pode multiplicar seu
value_out
por -1
UNION ambas as tabelas juntas e construa uma soma. Mas você ainda não obteria uma linha por um dia sem nenhum
value_in
ou value_out
, o que viola sua descrição. Portanto, a única solução limpa é ter uma tabela com todos os
(date, uid)
você quer no resultado e LEFT JOIN
as somas de table1
e table2
para ele, ou UNION ALL
os três (negativo table2
) em uma sub-seleção e, em seguida, some.