PROBLEM: Need query to return the MONTH and YIELD for Each Year. For some reason, if the data is not found in a Month a.Month the query will not return the b.Month’s Yield. I need the query to return all monthly data regardless of whether or not a.Month contains a month with data in the same months as “b”.
THE FOLLOWING RESULT: SHOULD RETURN A VALUE FOR “MONTH 1 YIELD_1”. But it doesn’t… because “MONTH 1 YIELD_0” does NOT contain a value for month 1.
**DATA RESULTS WITH: LEFT OUTER JOIN:**
Month Yield_1 Yield_0
2 11.44 14
3 NULL 3.21
4 NULL 14.24
7 NULL 10.36
8 NULL 0
9 NULL -9.6
10 NULL 10.35
11 NULL 1.4
12 11.44 -1.18
**DATA RESULTS WITH RIGHT OUTER JOIN:**
Month Yield_1 Yield_0
NULL 11.44 NULL
2 11.44 14
12 11.44 -1.18
QUERY:
SET @ID_CARTERA = 8;
select
a.Month Month,
b.Monthly_Yield Yield_Year_1,
a.Monthly_Yield Yield_Year_0
from
( select
LEFT(A.F_ANOMES, 4) Year,
RIGHT(A.F_ANOMES, 2) Month,
ROUND(A.POR_RENTABILIDAD, 2) Monthly_Yield
from dr_rent_carteras_meses A
where A.ID_CARTERA = @ID_CARTERA
And A.IND_RENTABILIDAD = 1
And LEFT(A.F_ANOMES, 4) = ( select MAX(left(F_ANOMES, 4 ) ) - 0 from dr_rent_carteras_meses where ID_CARTERA = @ID_CARTERA ) ) a
LEFT outer join
( select
LEFT(A.F_ANOMES, 4) Year,
RIGHT(A.F_ANOMES, 2) Month,
ROUND(A.POR_RENTABILIDAD, 2) Monthly_Yield
from dr_rent_carteras_meses A
where A.ID_CARTERA = @ID_CARTERA
And A.IND_RENTABILIDAD = 1
And LEFT(A.F_ANOMES, 4) = ( select MAX(left(F_ANOMES, 4 ) ) - 1 from dr_rent_carteras_meses where ID_CARTERA = @ID_CARTERA ) ) b on ( a.Month = b.Month )
order by month asc
Summary
I don’t think you need either left, right, or full join for this specific query as a
GROUP BY/CASEbased solution should work just fine and be at least twice as much faster.Problem Definition
I found this question rather interesting as it seems to arise from a real life situation and I believe that in real life
FULL JOINis seldom if ever necessary. So to me the real question is not how to combine the data from left and right joins but rather why is a full join needed in the first place?Besides, simple replacing
LEFTwithFULLwould not be enough as that would lead toNULLmonths for when the month is not available in the latest year.So I decided to go ahead and decipher the query.
Table and Data Setup
Unfortunately, @smileyseven didn’t provide table definitions or insert statements, so I had to work them out from the query and sample data. Based on the query syntax I’m assuming that SQL Server was used so that’s what I use as well.
Here’s my guess at how the table looks:
The important point ist hat
F_ANOMESis probably the key column as otherwise we would have to expect multiple rows for each month in the query output and that seems unlikely.The following insert statements should produce the sample data:
Solution
The first thing to note is that we don’t really need to calculate the maximum year two times, so we’ll start with this:
The
aandbtables are virtually same, so we could probably reuse them:and use the
FULL JOINbut I think a better option is to simply group it by month:One could use either the CTE version or re-write it without CTE as the query is simple enough:
The only drawback I’m aware of is that we get
0instead ofNULLfor the months where the data is missing and I’m not sure if that’s important.Performance
The performance of this query seems to be quite a bit better; in my setup the relative combined cost of the
GROUP BY/CASEquery with a separatedMAXis about 30% vs 70% forFULL JOINsolution.