1

我有一个由sku、storeperiod键入的销售表。由此,我需要一个返回包含今年去年信息的记录的查询。

下面的查询背后的逻辑是这样的:

  1. 计算去年的销售额(在 with 表中)
  2. 计算本年度销售额的主体(WHERE CLAUSE)
  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

似乎有多个问题。这个谓词:

WHERE spyypp BETWEEN 201305 AND 201305 

可能正在消除一些“外部连接”行。对于 spyypp,这些行将具有 NULL。(spsku 的分组有点奇怪,但这实际上可能不是问题,你只会得到单独的行......一个总共有匹配的 spsku,另一行没有匹配,但是那些购买 GROUP BY 都会崩溃,所以我不明白这一点。

如果你想使用公用表表达式,我想你想使用两个,并对这些结果集进行完全外连接。我会使用一个函数来为非匹配项获取非 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 中。


如果这实际上是针对 MySQL(而不是 SQL Server),那么我会这样写:

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 回答
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 回答