1

sku、store、およびperiodをキーとする sales テーブルがあります。このことから、今年昨年の両方の情報を含むレコードを返すクエリが必要です。

以下のクエリの背後にあるロジックは次のとおりです。

  1. 昨年の売上を計算する (with テーブル内)
  2. 今年の売上を本体で計算(WHERE節)
  3. 「LAST YEAR」テーブルをメイン テーブルに結合します。SKUとストアのみの入会(重複しないため、日付による入会はできません)

私の問題は、昨年の結果が全額ではないことです。私の結果は、LEFT JOIN を行っているかのように動作し、「LAST YEAR」テーブルからすべての結果を返すわけではありません。

追加の詳細:

  • LEFT JOIN と FULL OUTER JOIN を実行すると、同じ結果が得られます。
  • 「WITH」句を個別に実行すると、結果は正しい
  • 明細書全体を実行すると、昨年の売上は全額ではありません

以下のコードは一部簡略化されています...構文についてはそれほど心配していませんが、ロジックについてはもっと心配しています。誰かがアイデアを持っている場合、または私の論理の潜在的な欠陥を知っている場合、私は完全に耳を傾けます! 前もって感謝します!

WITH lastYear AS (                                                 
    SELECT 
        spsku "sku", 
        spstor "store", 
        sum(spales) "sales_ly"   
    FROM SALES                                              
    WHERE spyypp BETWEEN 201205 AND 201205 
    GROUP BY spstor, spsku
)                                                                  
SELECT 
    Sales_report.spstor "store", 
    sum(spales) "bom_retail", 
    sum(LY."sales_ly") "sales_ly"
FROM SALES Sales_report                              
FULL OUTER JOIN lastYear LY ON LY."sku" = spsku AND LY."store" = spstor
WHERE spyypp BETWEEN 201305 AND 201305      
GROUP BY spstor
4

3 に答える 3

1

この句は、結合が完了したWHERE spyypp BETWEEN 201305 AND 201305に実行されるため、結合を強制的に INNER JOIN にする結果をもたらします。

希望する効果を得るには、この句を次のように ON 条件に移動して、結合の前に句が適用されるようにする必要があります。

WITH lastYear AS (                                                 
    SELECT 
        spsku "sku", 
        spstor "store", 
        sum(spales) "sales_ly"   
    FROM SALES                                              
    WHERE spyypp BETWEEN 201205 AND 201205 
    GROUP BY spstor, spsku
)                                                                  
SELECT 
    Sales_report.spstor "store", 
    sum(spales) "bom_retail", 
    sum(LY."sales_ly") "sales_ly"
FROM SALES Sales_report                              
FULL OUTER JOIN lastYear LY
    ON LY."sku" = spsku
   AND LY."store" = spstor
   AND spyypp BETWEEN 201305 AND 201305      
GROUP BY spstor

または、状況によってはより明確なコードを提供するために、LAST_YEAR と THIS_YEAR の両方の共通テーブル式を次のように作成します。

WITH 
lastYear AS (                                                 
    SELECT 
        spsku "sku", 
        spstor "store", 
        sum(spales) "sales_ly"   
    FROM SALES                                              
    WHERE spyypp BETWEEN 201205 AND 201205 
    GROUP BY spstor, spsku
),
this year as (
    SELECT 
        spsku "sku", 
        spstor "store", 
        sum(spales) "sales_ly"   
    FROM SALES                                              
    WHERE spyypp BETWEEN 201305 AND 201305 
    GROUP BY spstor, spsku
)                                                                  
SELECT 
    TY.spstor "store", 
    sum(TY.spales) "bom_retail", 
    sum(LY."sales_ly") "sales_ly"
FROM this year TY
FULL OUTER JOIN lastYear LY
    ON LY."sku"   = TY.sku
   AND LY."store" = TY.stor
于 2013-07-12T01:51:46.040 に答える
0

ご提案いただきありがとうございます。SQL を再構築して、今年と昨年の両方を with 句内にネストしました。私が見過ごしていた致命的な欠陥は、主要な節で sku によって選択/グループ化しない限り、昨年のデータセットにのみ存在する sku が含まれていなかったことです。

この問題を解決するために、以下のコードを使用しました。TY/LY 売上のプレースホルダーを含むデータセットを個別に作成しました。次に、UNION を実行してテーブルを結合しました (TY/LY は異なる列と異なる行に格納されています)。それをすべてサブクエリに詰め込みました。データを合計していたため (合計されていないフィールドでグループ化)、これによりすべての行が折りたたまれ、目的の形式に適切に反映されます。

WITH lastYear AS (                                                
   SELECT sku, store, sum(sales) "sales_ly"  
   FROM DWHLIB.SLSSUMPD                                             
   WHERE spyypp BETWEEN 201205 AND 201205    
   GROUP BY store, sku
),                                                                
thisYear AS (                                                     
   SELECT spsku sku, store, sum(sales) "sales"     
   FROM DWHLIB.SLSSUMPD                                             
   WHERE spyypp BETWEEN 201305 AND 201305    
   GROUP BY store, sku                                        
)
SELECT sum(AY."sales"), sum(AY."sales_ly"), AY."store"                                                                 
FROM (
    SELECT sum(TY."sales") "sales", 0 "sales_ly", TY."store"
    FROM thisYear TY GROUP BY TY."store"                              
    UNION ALL                                                         
    SELECT  0 "sales", sum(LY."sales_ly") "sales_ly", LY."store"
    FROM lastYear LY
    GROUP BY LY."store"
) AY
GROUP BY "store"    
于 2013-07-12T20:34:29.203 に答える
0

複数の問題があるようです。この述語:

WHERE spyypp BETWEEN 201305 AND 201305 

おそらく「外部結合」行の一部を削除しています。これらの行には、spyypp の NULL が含まれます。(spsku によるグループ化は少し奇妙ですが、それは実際には問題ではないかもしれません。別々の行を取得するだけです...一致する spsku があった 1 つの合計と、一致しなかった別の行ですが、それらはGROUP BYを購入するとすべてが崩壊するので、意味がわかりません。

共通のテーブル式を使用する場合は、2 つ使用し、それらの結果セットに対して完全外部結合を実行する必要があると思います。一致しない場合に NULL 以外の値を取得する関数を使用します。これには ISNULL 関数が便利です。

WITH lastYear AS
(
    SELECT 
        spsku,
        spstor,
        sum(spales) AS sales_ly
    FROM SALES
    WHERE spyypp BETWEEN 201205 AND 201205
    GROUP BY spstor, spsku
)
, thisYear AS (
    SELECT 
        spsku,
        spstor,
        SUM(spales) AS sales_ty
    FROM SALES
    WHERE spyypp BETWEEN 201305 AND 201305
    GROUP BY spstor, spsku
)
SELECT ISNULL(thisYear.spstor,lastYear.spstor) AS "store"
     , SUM(TY.sales_ty) AS "bom_retail"
     , SUM(LY.sales_ly) AS "sales_ly"
  FROM thisYear TY
  FULL
 OUTER
  JOIN lastYear LY
    ON LY.spsku = TY.spsku 
   AND LY.store = TY.store
 GROUP
    BY ISNULL(thisYear.spstor,lastYear.spstor)

それがあなたが求めている結果セットである場合、それは不要なノイズのように思えます。返される spsku とその完全な外部結合に関心がない場合、このクエリは同等の結果セットを返します。

SELECT r.spstor AS "store"
     , SUM(CASE WHEN r.spyypp BETWEEN 201305 AND 201305 THEN r.spsales END) AS "bom_retail"
     , SUM(CASE WHEN r.spyypp BETWEEN 201205 AND 201205 THEN r.spsales END) AS "sales_ly"
  FROM SALES r
 WHERE r.spyypp BETWEEN 201305 AND 201305
    OR r.spyypp BETWEEN 201205 AND 201205
 GROUP
    BY r.spstor

ここでの「トリック」は、条件付きテストを使用して、spsales の金額を SUM に含めるかどうかを決定することです。


これが実際に (SQL Server ではなく) MySQL 用である場合、次のように記述します。

SELECT r.spstor AS `store`
     , SUM(IF(r.spyypp BETWEEN 201305 AND 201305,r.spsales,NULL)) AS `bom_retail`
     , SUM(IF(r.spyypp BETWEEN 201205 AND 201205,r.spsales,NULL)) AS `sales_ly`
  FROM SALES r
 WHERE r.spyypp BETWEEN 201305 AND 201305
    OR r.spyypp BETWEEN 201205 AND 201205
 GROUP
    BY r.spstor
于 2013-07-11T23:19:43.900 に答える