1

问题:需要查询以返回每年的 MONTH 和 YIELD。出于某种原因,如果在 a.Month 月份未找到数据,则查询将不会返回 b.Month 的产量。我需要查询返回所有月度数据,无论 a.Month 是否包含与“b”相同月份的数据。

以下结果:应该为“MONTH 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

询问:

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
4

2 回答 2

0

尝试完全外连接。看这里:

http://en.wikipedia.org/wiki/Join_%28SQL%29#Full_outer_join

于 2012-12-09T20:12:24.690 回答
0

概括

我认为对于这个特定的查询,您不需要左连接、右连接或完全连接,因为基于GROUP BY/CASE的解决方案应该可以正常工作,并且速度至少要快两倍。

问题定义

我发现这个问题很有趣,因为它似乎来自现实生活中的情况,我相信在现实生活FULL JOIN中很少有必要。所以对我来说,真正的问题不是如何组合左右连接的数据,而是为什么首先需要完全连接?

此外,简单的替换LEFTFULL是不够的,因为这会导致

  1. 相同月份的重复行;
  2. 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% 和 70% FULL JOIN

于 2012-12-12T23:12:46.687 回答