Exercise #30

Under the assumption that the income (inc) and expenses (out) of the money at each outlet (point) are registered any number of times a day, get a result set with fields: outlet, date, expense, income. Note that a single record must correspond to each outlet at each date. Use Income and Outcome tables.

This task is required to gather data from two tables in one resultant set so the income and the outcome in one point must be in one row.

Similar task (29) for Income_o and Outcome_o tables doesnt cause any problems as usual. The problems root is demonstrated by following solution.

Solution 2.1.1

SELECT Income.point, Income.date, SUM(out), SUM(inc)
FROM Income LEFT JOIN
Outcome ON Income.point = Outcome.point AND
Income.date = Outcome.date
GROUP BY Income.point, Income.date
UNION
SELECT Outcome.point, Outcome.date, SUM(out), SUM(inc)
FROM Outcome LEFT JOIN
Income ON Income.point = Outcome.point AND
Income.date = Outcome.date
GROUP BY Outcome.point, Outcome.date;
mssql
🚫
[[ error ]]
[[ column ]]
[[ value ]]

The idea is in the joining of table with incomes and with outcomes by equality of point`s number and a date. Left join guarantees right result in case when there is some days with income only (outcome is NULL). Then it unions with an opposite query which has left join the outcomes table with the incomes table. This takes into account opposite situation when there is outcome and income is NULL. The duplicates are removed by UNION clause.

The query 2.1.1 returns wrong result if many income/outcome operations at one point happens in one day. As example for this situation we get typical day: March 24, 2001. Let`s execute a couple of queries:

SELECT * FROM Income
WHERE date = '2001-03-24 00:00:00.000' AND point = 1;
mssql
🚫
[[ error ]]
[[ column ]]
[[ value ]]

SELECT * FROM Outcome
WHERE date = '2001-03-24 00:00:00.000' AND point = 1;
mssql
🚫
[[ error ]]
[[ column ]]
[[ value ]]

We get such result:

Income

codepointdateinc
312001-03-24 00:00:00.0003600
1112001-03-24 00:00:00.0003400

Outcome

codepointdateout
212001-03-24 00:00:00.0003663
1312001-03-24 00:00:00.0003500

In case when there are both: incomes and outcomes, outer join and inner join are the same. Every single row from one table joins with every row from other one if the date and the points number are equal. Thats why before data is grouping such result would be returned (the income and outcome columns are only displayed):

incout
36003663
36003500
34003663
34003500

After grouping and summarizing we get doubling of the result as for income as well for outcome. If there would be three incomes, we would get tripling of outcome and so on.

The duplicates aren`t matter, because each query in union returns analogous result: there is only one row for each pair {point, date}.

T&S

To solve the problem on SQL-EX.RU