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.