问题:需要查询才能返回每年的MONTH和YIELD。出于某种原因,如果在月份a.Month中找不到数据,则查询将不返回b.Month的Yield。我需要查询返回所有月度数据,无论a.Month是否包含与“b”相同月份的数据的月份。
以下结果:应该返回“月份1 YIELD_1”的值。但它没有...因为“MONTH 1 YIELD_0”不包含第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
答案 0 :(得分:0)
尝试FULL OUTER JOIN。见这里:
答案 1 :(得分:0)
我认为您不需要对此特定查询进行左,右或完全联接,因为基于GROUP BY
/ CASE
的解决方案应该可以正常工作并且速度至少快两倍。
我发现这个问题相当有趣,因为它似乎来自现实生活中的情况,我相信在现实生活中FULL JOIN
很少有必要。所以对我来说真正的问题不是如何组合来自左右连接的数据,而是为什么首先需要完全连接?
此外,简单地用LEFT
替换FULL
是不够的,因为这会导致
NULL
个月,因为最近一年没有月份。所以我决定继续解密查询。
不幸的是,@ smileyseven没有提供表定义或插入语句,所以我不得不从查询和示例数据中解决它们。根据查询语法,我假设使用了SQL Server,这也是我使用的。
这是我对表格外观的猜测:
CREATE TABLE dr_rent_carteras_meses
(
F_ANOMES varchar(6) NOT NULL PRIMARY KEY,
POR_RENTABILIDAD float NOT NULL,
-- These columns are irrelevant
ID_CARTERA INT NOT NULL DEFAULT(8),
IND_RENTABILIDAD INT DEFAULT(1) NOT NULL
)
重要的一点是F_ANOMES
可能是关键列,否则我们不得不期望查询输出中每个月有多行,这似乎不太可能。
以下插入语句应生成示例数据:
INSERT dr_rent_carteras_meses (F_ANOMES, POR_RENTABILIDAD) VALUES
('201202', 14),
('201203', 3.21),
('201204', 14.24),
('201207', 10.36),
('201208', 0),
('201209', -9.6),
('201210', 10.35),
('201211', 1.4),
('201212', -1.18),
('201101', 11.44),
('201102', 11.44),
('201112', 11.44)
首先要注意的是,我们并不需要两次计算最大年份,所以我们将从这开始:
declare @Max_Year int
select
@Max_Year = MAX(left(F_ANOMES, 4))
from dr_rent_carteras_meses
where ID_CARTERA = @ID_CARTERA
a
和b
表几乎相同,因此我们可能会重复使用它们:
;with
Monthly_Yield_CTE as
(
select
LEFT(F_ANOMES, 4) Year,
RIGHT(F_ANOMES, 2) Month,
ROUND(POR_RENTABILIDAD, 2) Monthly_Yield
from dr_rent_carteras_meses
where ID_CARTERA = @ID_CARTERA
and IND_RENTABILIDAD = 1
and LEFT(F_ANOMES, 4) in (@Max_Year, @Max_Year - 1)
)
并使用FULL JOIN
,但我认为更好的选择是按月分组:
select
[Month],
SUM(CASE WHEN [Year] = @Max_Year - 1 THEN Monthly_Yield ELSE 0 END) Yield_Year_1,
SUM(CASE WHEN [Year] = @Max_Year THEN Monthly_Yield ELSE 0 END) Yield_Year_0
from Monthly_Yield_CTE
group by [Month]
order by [Month]
可以使用CTE版本或在没有CTE的情况下重写它,因为查询很简单:
SET @ID_CARTERA = 8
declare @Max_Year int
select
@Max_Year = MAX(left(F_ANOMES, 4))
from dr_rent_carteras_meses
where ID_CARTERA = @ID_CARTERA
select
RIGHT(F_ANOMES, 2) Month,
SUM(CASE
WHEN LEFT(F_ANOMES, 4) = @Max_Year - 1
THEN ROUND(POR_RENTABILIDAD, 2)
ELSE 0
END) Yield_Year_1,
SUM(CASE
WHEN LEFT(F_ANOMES, 4) = @Max_Year
THEN ROUND(POR_RENTABILIDAD, 2)
ELSE 0
END) Yield_Year_0
from dr_rent_carteras_meses
where ID_CARTERA = @ID_CARTERA
and IND_RENTABILIDAD = 1
and LEFT(F_ANOMES, 4) in (@Max_Year, @Max_Year - 1)
group by RIGHT(F_ANOMES, 2)
order by 1
我所知道的唯一缺点是,在数据丢失的几个月内,我们得到的是0
而不是NULL
,我不确定这是否重要。
<强>性能强>
这个查询的表现似乎好一点;在我的设置中,GROUP BY
/ CASE
查询与分隔MAX
的相对合计费用约为30%,而FULL JOIN
解决方案则为70%。