GROUP BY & SUM значений с пропущенными МЕСЯЦАМИ - PullRequest
0 голосов
/ 24 сентября 2018

Я просмотрел множество примеров и присоединился к нескольким из них, чтобы перейти к следующему утверждению:

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 сможет показать мне правильное направление в этом.

Спасибо

Ответы [ 2 ]

0 голосов
/ 24 сентября 2018

Более общий подход заключается в применении фильтра перед присоединением.

;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 или других сложных запросов может оказаться чрезвычайно полезным отфильтровать источники в одной области и объединить их в отдельной области.

(я всегда фильтрую источники, я ненавижу кусковатыйкетчуп.)

0 голосов
/ 24 сентября 2018

Вам нужно переместить условие на 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;
...