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

FULL OUTER JOIN を試してください。ここを参照してください:

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

于 2012-12-09T20:12:24.690 に答える
0

概要

GROUP BY/CASEベースのソリューションは問題なく動作し、少なくとも 2 倍高速になるはずなので、この特定のクエリに対して左結合、右結合、または完全結合のいずれも必要ないと思います。

問題定義

この質問は、実際の状況から発生しているように見えるので、かなり興味深いと思いました。実際の生活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)

解決

最初に注意すべきことは、実際には最大年を 2 回計算する必要はないので、次のことから始めます。

declare @Max_Year int
select 
    @Max_Year = MAX(left(F_ANOMES, 4))
from dr_rent_carteras_meses 
where ID_CARTERA = @ID_CARTERA

abテーブルは実質的に同じなので、おそらく再利用できます。

;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の 70% に対して約 30%です。FULL JOIN

于 2012-12-12T23:12:46.687 に答える