【问题标题】:GROUP BY & SUM of values with missing MONTHSGROUP BY & SUM 缺失 MONTHS 的值
【发布时间】:2018-09-24 14:42:21
【问题描述】:

我已经浏览了很多示例,并加入了其中的几个,以便得出以下陈述;

DECLARE @StartDate SMALLDATETIME, @EndDate SMALLDATETIME;

SELECT @StartDate = '20170930', @EndDate = '20180930';

;WITH d(d) AS 
(
  SELECT DATEADD(MONTH, n, DATEADD(MONTH, DATEDIFF(MONTH, 0, @StartDate), 0))
  FROM ( SELECT TOP (DATEDIFF(MONTH, @StartDate, @EndDate) + 1) 
    n = ROW_NUMBER() OVER (ORDER BY [object_id]) - 1
    FROM sys.all_objects ORDER BY [object_id] ) AS n
)

SELECT 
  [Period]    = CONVERT(VARCHAR(4), YEAR(d.d)) + '-' + CONVERT(VARCHAR(2), MONTH(d.d)),
  QtyTotal = ISNULL(SUM(o.QEXIT),0)
FROM d LEFT OUTER JOIN VE_STOCKTRANS AS o
  ON o.TRANSDATE >= d.d

  AND o.TRANSDATE < DATEADD(MONTH, 1, d.d)
 WHERE STOCKID = 6000 AND TRANSTYPE = 3553
GROUP BY d.d
ORDER BY d.d;

我需要获取某件商品在过去一年的总销售量。如果该商品在该特定月份没有任何销售额,则该月份旁边应显示 0。除非提供了 WHERE 子句,否则上述查询会执行所需的操作。一旦我添加 WHERE 子句来获取特定产品的数据,没有销售的月份就会消失。

如果有经验的 SQL 开发人员能告诉我正确的方向,我将不胜感激。

谢谢

【问题讨论】:

    标签: sql sql-server tsql common-table-expression


    【解决方案1】:

    您需要将条件移至ON:

    -- ...
    SELECT 
      [Period] = CONVERT(VARCHAR(4),YEAR(d.d)) +'-'+ CONVERT(VARCHAR(2), MONTH(d.d)),
      QtyTotal = ISNULL(SUM(o.QEXIT),0)
    FROM d LEFT OUTER JOIN VE_STOCKTRANS AS o
      ON o.TRANSDATE >= d.d
    
      AND o.TRANSDATE < DATEADD(MONTH, 1, d.d)
      AND STOCKID = 6000 AND TRANSTYPE = 3553   -- here
    GROUP BY d.d
    ORDER BY d.d;
    

    【讨论】:

    • :S 上一次让我这么难堪是在我第一次被我约出来的女孩拒绝的时候。谢谢 :)
    【解决方案2】:

    更通用的方法是在加入之前应用过滤器。

    ;WITH d(d) AS 
    (
      SELECT DATEADD(MONTH, n, DATEADD(MONTH, DATEDIFF(MONTH, 0, @StartDate), 0))
      FROM ( SELECT TOP (DATEDIFF(MONTH, @StartDate, @EndDate) + 1) 
        n = ROW_NUMBER() OVER (ORDER BY [object_id]) - 1
        FROM sys.all_objects ORDER BY [object_id] ) AS n
    ),
      o AS
    (
      SELECT *
        FROM VE_STOCKTRANS
       WHERE STOCKID = 6000
         AND TRANSTYPE = 3553
    )
    SELECT 
      [Period] = CONVERT(VARCHAR(4), YEAR(d.d)) + '-' + CONVERT(VARCHAR(2), MONTH(d.d)),
      QtyTotal = ISNULL(SUM(o.QEXIT),0)
    FROM
      d
    LEFT OUTER JOIN
      o
        ON  o.TRANSDATE >= d.d
        AND o.TRANSDATE < DATEADD(MONTH, 1, d.d)
    GROUP BY
      d.d
    ORDER BY
      d.d;
    

    正如您在其他答案中看到的那样,这里并不是绝对必要的。但是,在执行 FULL OUTER JOIN 或其他复杂查询时,在一个范围内过滤您的源并加入另一个范围内会非常有帮助。

    (我总是过滤我的消息来源,我讨厌结块的番茄酱。)

    【讨论】:

    • 感谢您的回答。我接受了第一个工作答案。您首先过滤数据的想法实际上非常重要。你能多谈谈“非常有帮助”这个短语吗?
    • @KemalEmin - 它隔离了每个 CTE 或子查询的职责,使应用的逻辑更清晰,并可能降低后续连接或 WHERE 子句的复杂性。总体而言,它提高了可维护性、可测试性、可读性和性能。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-01-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多