-3

I have two tables such as

  1. Income(point, date, inc)
  2. Outcome(point, date, out)

where point and date are the primary key.
I need to find out the total income inc and outcome out on any given date. My answer

WITH all_date AS
(SELECT point, date FROM income
UNION
SELECT point, date FROM outcome)
SELECT a.point, a.date, SUM(inc), SUM(out)
FROM all_date a LEFT JOIN income i ON i.point=a.point AND i.date=d.date
                LEFT JOIN outcome o ON o.point=a.point AND o.date=a.date
GROUP BY a.point, a.date

But I am getting wrong result. Because the all_date LEFT JOIN income while trying to do LEFT JOIN with outcome duplicates certain rows from income, hence messing with the final SUM.

Basically I want to LEFT JOIN the third table outcome with all_date not with all_date LEFT JOIN income. Refer to Qus No 30. of http://www.sql-ex.ru/learn_exercises.php for further clarification

Ivan Starostin
  • 8,798
  • 5
  • 21
  • 39
Bikash Behera
  • 434
  • 5
  • 12

4 Answers4

4

Why not do that join first then?

or even better, just do a full outer join:

Select coalesce(o.point, i.point) point,
   coalesce(o.Date, i.date) date
From income i full join outcome o
  on o.point=i.point 
     and o.date=i.date
group by coalesce(o.point, i.point),
     coalesce(o.Date, i.date)

and, since you're not actually using any aggregation functions, a distinct would work as well:

Select distinct
   coalesce(o.point, i.point) point,
   coalesce(o.Date, i.date) date
From income i full join outcome o
  on o.point=i.point 
     and o.date=i.date

My apologies, I'm not a MySQL guy and did not realize that MySQL does not have Full Join syntax. but there is a workaround. look at the following link:

Full Join in MYSQL

basically you need a Union, (close to what you were doing, actually)

select point, date 
from income i
 left join outcome o 
    on o.point=i.point 
      and o.date=i.date  
  UNION                 -- <-- leave out the ALL to eliminate duplicates
select point, date 
from outcome o
 right join income i 
    on i.point=o.point 
      and i.date=o.date  
Community
  • 1
  • 1
Charles Bretana
  • 143,358
  • 22
  • 150
  • 216
  • Just realized MySQL doesn't support FULL JOIN. Any solution for that? – Bikash Behera Dec 27 '16 at 14:43
  • My apologies, I'm not a MySQL guy and did not realize that. But check this out... as mentioned in link in my answer – Charles Bretana Dec 27 '16 at 14:54
  • @BikashBehera don't confuse people - you tagged tour question with MS SQL SERVER dbms. – Ivan Starostin Dec 27 '16 at 16:06
  • @IvanStarostin Yes, sorry about that. I actually tagged with both MSSQL and MySQL as the exercise is in MSSQL and I was trying to solve the exercise on my PC with MySQL. Then the initial question editor removed the mysql tag later on. – Bikash Behera Dec 28 '16 at 08:09
0

I do not know what is the purpose of using table expression here, you can get the result by using one join here:

SELECT i.point, i.date, SUM(inc), SUM(out)
FROM  income i 
LEFT JOIN outcome o   
ON o.point=i.point AND o.date=i.date
GROUP BY i.point, i.date
LONG
  • 4,490
  • 2
  • 17
  • 35
  • uni-directional outer join will skip rows in one side. – Charles Bretana Dec 27 '16 at 14:32
  • @LONG in your query you will drop out the rows from right table `outcome` which has no match in left table `income`. To get all the `point-date` I used the CTE – Bikash Behera Dec 27 '16 at 14:35
  • I see, then use `INNER JOIN` if you only want to filter out those common date. Just change `LEFT JOIN` to `INNER JOIN` in my answer. And, based on your comment, I am guessing you do not want to miss any date no matter there exists both `inc` and `out`, then try : SELECT i.point, i.date, SUM(ISNULL(i.inc,0)), SUM(ISNULL(o.out,0)) FROM income i FULL JOIN outcome o ON o.point=i.point AND o.date=i.date GROUP BY i.point, i.date – LONG Dec 27 '16 at 14:48
0

MS-SQL sp for your problem:

CREATE PROCEDURE dototals
@date DATETIME
AS
BEGIN

SELECT point,SUM(ISNULL(inc,0)) as inc into #tmp_i FROM Income WHERE date =@date  GROUP BY point

SELECT point,SUM(ISNULL(out,0)) as out into #tmp_d FROM Outcome WHERE date =@date  GROUP BY point

SELECT DISTINCT point into #tmp_p FROM 
(SELECT point FROM #tmp_i
UNION ALL
SELECT point FROM #tmp_o)

SELECT @date as date, t1.point as point, t2.out as outcome,t3.inc as income 
FROM #tmp_p as t1
LEFT JOIN #tmp_o as t2 on t1.point=t2.point
LEFT JOIN #tmp_i as t3 on t1.point=t3.point
END
Alex Banu
  • 28
  • 3
0

Here is my final solution in MSSQL. But I guess using COALESCE with FULL JOIN works the best.

    WITH all_date AS
    (SELECT point, date FROM income
    UNION
    SELECT point, date FROM outcome)

    SELECT a.point, a.date,
    (SELECT SUM(o.out) FROM outcome o WHERE o.point=a.point AND o.date=a.date) AS outcome,
    (SELECT SUM(i.inc) FROM income i WHERE i.point=a.point AND i.date=a.date) AS income

    FROM all_date a
Bikash Behera
  • 434
  • 5
  • 12