SQL - 跟踪月度销售额

时间:2017-11-29 22:22:54

标签: sql sql-server counting

我正在编写一个查询,按月汇总销售情况。我的问题是我的查询只返回销售月份的记录。例如,我正在寻找15个月的范围。但是对于下面例子中的一个特定部分,15个月中只有3个有销售。

我希望有15条记录出现,其他的则有0条出售。我希望获得额外记录的原因是我想采用这个标准差,而丢弃记录会影响计算。

示例代码:

SELECT I.PartNumber as PartNumber,
YEAR(O.CreateDate) as CreateDateYear,
MONTH(O.CreateDate) as CreateDateMonth,
COUNT(*) as TotalDemand
FROM OrderDetails OD
INNER JOIN Orders O on O.Id = OD.OrderId
INNER JOIN Items I on I.Id = OD.ItemId
WHERE 
O.CreateDate >= '1-1-2016' 
AND O.CreateDate <= '3-31-2017'
AND I.PartNumber = '5144831-2'
GROUP BY I.PartNumber, YEAR(O.CreateDate) , MONTH(O.CreateDate);

示例电流输出:

Part # | Year | Month | Demand
5144831-2   2017    1   1
5144831-2   2017    2   3
5144831-2   2016    3   1

期望输出:

我想要一个额外的行,例如:

5144831-2   2016    11  0

显示2016年11月没有销售。

我确实有一个临时表#_date_array2,可能有几个月/年,我想我需要帮助合并LEFT JOIN。

3 个答案:

答案 0 :(得分:1)

假设您每个月都有某事的销售,最简单的解决方案是切换到条件聚合:

SELECT '5144831-2' as PartNumber,
       YEAR(O.CreateDate) as CreateDateYear,
       MONTH(O.CreateDate) as CreateDateMonth,
       SUM(CASE WHEN I.PartNumber = '5144831-2' THEN 1 ELSE 0 END) as TotalDemand
FROM OrderDetails OD INNER JOIN
     Orders O 
     ON O.Id = OD.OrderId INNER JOIN
     Items I 
     ON I.Id = OD.ItemId
WHERE O.CreateDate >= '2016-01-01' AND
      O.CreateDate <= '2017-03-31'
GROUP BY YEAR(O.CreateDate) , MONTH(O.CreateDate);

注意:这是解决问题的方法。更强大的解决方案涉及生成日期并使用LEFT JOIN(或类似功能)。但是,这通常是获得结果的最快方式。

答案 1 :(得分:1)

如果要使用左连接,则无法直接将其与内连接一起使用。您可以在括号内进行内部连接,然后在外面进行左连接,以避免弄乱左连接的结果。试试这个:

SELECT Z.PartNumber as PartNumber,
YEAR(O.CreateDate) as CreateDateYear,
MONTH(O.CreateDate) as CreateDateMonth,
COUNT(Z.OrderId) as TotalDemand
FROM Orders O 
LEFT JOIN 
(
    SELECT OrderId, PartNumber
    FROM
    OrderDetails OD 
    INNER JOIN Items I ON I.Id = OD.ItemId
    AND I.PartNumber = '5144831-2'
) Z
ON O.Id = Z.OrderId 
AND O.CreateDate >= '1-1-2016' 
AND O.CreateDate <= '3-31-2017'
GROUP BY Z.PartNumber, YEAR(O.CreateDate) , MONTH(O.CreateDate);

要在没有订单的情况下获得0个月的计数,请避免使用count(*)并使用上面给出的count(OrderId)。

注意 - 您必须确保订单表中包含所有月份和年份,即2016年11月在CreateDate表中没有Orders值(左表中)加入),输出也不会产生这个月的条目。

修改 你能试试这个:

SELECT Z.PartNumber as PartNumber,
YEAR(O.CreateDate) as CreateDateYear,
MONTH(O.CreateDate) as CreateDateMonth,
COUNT(O.OrderId) as TotalDemand
FROM Orders O 
RIGHT JOIN 
(
    SELECT OrderId, PartNumber
    FROM
    OrderDetails OD 
    INNER JOIN Items I ON I.Id = OD.ItemId
    AND I.PartNumber = '5144831-2'
) Z
ON O.Id = Z.OrderId 
AND O.CreateDate >= '1-1-2016' 
AND O.CreateDate <= '3-31-2017'
GROUP BY Z.PartNumber, YEAR(O.CreateDate) , MONTH(O.CreateDate);

答案 2 :(得分:0)

基于您对其他帖子等的所有评论,您似乎拥有一个具有所需日期范围的表格,并且您希望能够对多个/所有部件号码运行分析。因此,主要问题是您需要在日期表和在此期间销售的零件号之间进行笛卡尔联接,以便在未售出时完成您的操作。

;WITH cteMaxMinDates AS (
    SELECT
       MinDate = MIN(DATEFROMPARTS(CreateDateYear,CreateDateMonth,1))
       ,MaxDate = MAX(DATEFROMPARTS(CreateDateYear,CreateDateMonth,1))
    FROM
       #_date_array2
)

;WITH cteOrderDetails AS (
    SELECT
       d.CreateDateYear
       ,d.CreateDateMonth
       ,I.PartNumber
    FROM
       #_date_array2 d
       INNER JOIN Orders o
       ON d.CreateDateMonth = MONTH(o.CreateDate)
       AND d.CreateDateYear = YEAR(o.CreateDate)
       INNER JOIN OrderDetails od
       ON o.Id = od.OrderId
       INNER JOIN Items i
       ON od.ItemId = i.Id
       AND i.PartNumber = '5144831-2'
)

, cteDistinctParts AS (
    SELECT DISTINCT PartNumber
    FROM
       cteOrderDetails
)

SELECT
    d.CreateDateYear
    ,d.CreateDateMonth
    ,I.PartNumber
    ,COUNT(od.PartNumber) as TotalDemand
FROM
    #_date_array2 d
    CROSS JOIN cteDistinctParts p
    LEFT JOIN cteOrderDetails od
    ON d.CreateDateYear = od.CreateDateYear
    AND d.CreateDateMonth = od.CreateDateMonth
    AND p.PartNumber = od.PartNumber
GROUP BY
    d.CreateDateYear
    ,d.CreateDateMonth
    ,I.PartNumber

要获取所有部件号,只需删除AND i.PartNumber = '5144831-2'加入条件。