B1查询 |不同时间段(即 1 / 3 / 6 / 12 个月)的月度销售额合并

B1 query | Monthly sales consolidated for different time periods (i.e. 1 / 3 / 6 / 12 months)

真的很挣扎这个。寻找一种查询不同时间跨度的销售量的方法,所有这些都放在一个 table.

假设现在是 8 月 13 日。然后我想汇总销售量:

我尝试重用数据透视查询示例中的片段,这些片段可以找到与销售量相关但未能成功。 我从头开始,首先尝试创建日期时间,我可以将其用于时间跨度,但这已经非常繁琐,而且不知何故感觉不对。

我认为我需要以 4 个单一查询结束,然后需要将这些查询连接起来以将所有列合并为一个 table:

ItemName ItemCode Sal.vol 1 mth Sal.vol 3 mths Sal.vol 6 mths Sal.vol 12 mths
Item 1 10102251 10 30 60 120
Item 2 10120101 14 35 78 181

目前我的进度:

SELECT
  T1.itemcode,  month(T1.[docDate]) as month, T3.ItemName,
  SUM(t1.quantity )
FROM INV1 T1 INNER JOIN OINV T2 ON T1.docentry = T2.docentry INNER JOIN OITM T3 ON T1.ItemCode = T3.ItemCode
WHERE T1.[docDate] between DATEADD(month, -4, GETDATE()) and DATEADD(month, -1, GETDATE()) AND T1.ItemCode LIKE '1%' AND T3.ItmsGrpCod = 100
Group By  T1.itemcode, T3.ItemName, month(T1.[docDate])

对于我的约会时间,我想按如下方式构建它们:

DECLARE @date date = month(DATEADD(month, -1, GETDATE())) + '-01-' + year(DATEADD(month, -1, GETDATE()));
DECLARE @datetime datetime = @date;     
SELECT @datetime AS '@datetime'

我还没有成功,因为我在转换 int 到日期时遇到问题,我认为 1 月至 9 月的 month() 将不起作用,因为它 return 只有 1 位数字...

谁能帮我指明正确的方向?

提前致谢!


更新 1:

@imerd 为我指出了正确的方向。我能够根据需要构建查询。分享我的中间结果,因为这目前有效。查询需要一些清理和优化,并将重复出现的主要部分外包到第二个函数中。

create function MonthFirst (@period integer ) returns date
as begin
declare @returnperiod date 
set @returnperiod = cast(cast(year(DATEADD(month, @period, GETDATE())) as varchar(4)) + '-' +
    cast(month(DATEADD(month, @period, GETDATE())) as varchar(2)) + '-01' as date)
 return @returnperiod
end
-- drop function dbo.MonthFirst

SELECT S12.ItemCode, o1.ItemName, S12.[last 12 months], S6.[last 6 months], S3.[last 3 months], S1.[last month] FROM 
(SELECT
   T1.itemcode,  CAST(SUM(t1.quantity) AS int) AS 'last 12 months'
FROM DLN1 T1 INNER JOIN ODLN T2 ON T1.docentry = T2.docentry INNER JOIN OITM T3 ON T1.ItemCode = T3.ItemCode
WHERE T1.[docDate] between CAST(dbo.MonthFirst(-12) AS datetime) AND  DATEADD(second, -1, CAST(dbo.MonthFirst(0) AS datetime)) 
      AND T3.validFor = 'Y' AND T3.ItmsGrpCod = 100 --products / 102 raw materials
      AND T2.CANCELED = 'N'
Group By T1.itemcode) S12

FULL JOIN 

(SELECT
   T1.itemcode,  CAST(SUM(t1.quantity) AS int) AS 'last 6 months'
FROM DLN1 T1 INNER JOIN ODLN T2 ON T1.docentry = T2.docentry INNER JOIN OITM T3 ON T1.ItemCode = T3.ItemCode
WHERE T1.[docDate] between CAST(dbo.MonthFirst(-6) AS datetime) AND  DATEADD(second, -1, CAST(dbo.MonthFirst(0) AS datetime)) 
      AND T3.validFor = 'Y' AND T3.ItmsGrpCod = 100 --products / 102 raw materials
      AND T2.CANCELED = 'N'
Group By T1.itemcode) S6 on S12.ItemCode = S6.ItemCode

FULL JOIN 

(SELECT
   T1.itemcode,  CAST(SUM(t1.quantity) AS int) AS 'last 3 months'
FROM DLN1 T1 INNER JOIN ODLN T2 ON T1.docentry = T2.docentry INNER JOIN OITM T3 ON T1.ItemCode = T3.ItemCode
WHERE T1.[docDate] between CAST(dbo.MonthFirst(-3) AS datetime) AND  DATEADD(second, -1, CAST(dbo.MonthFirst(0) AS datetime)) 
      AND T3.validFor = 'Y' AND T3.ItmsGrpCod = 100 --products / 102 raw materials
      AND T2.CANCELED = 'N'
Group By T1.itemcode) S3 on S12.ItemCode = S3.ItemCode

FULL JOIN 

(SELECT
   T1.itemcode,  CAST(SUM(t1.quantity) AS int) AS 'last month'
FROM DLN1 T1 INNER JOIN ODLN T2 ON T1.docentry = T2.docentry INNER JOIN OITM T3 ON T1.ItemCode = T3.ItemCode
WHERE T1.[docDate] between CAST(dbo.MonthFirst(-1) AS datetime) AND  DATEADD(second, -1, CAST(dbo.MonthFirst(0) AS datetime)) 
      AND T3.validFor = 'Y' AND T3.ItmsGrpCod = 100 --products / 102 raw materials
      AND T2.CANCELED = 'N'
Group By T1.itemcode) S1 on S12.ItemCode = S1.ItemCode

INNER JOIN OITM o1 on S12.ItemCode = o1.ItemCode

ORDER BY o1.ItemName

更新 2:

我现在结合了来自@imerd 和@Gordon Linoff 的 suggestions/hints 并得到了这个漂亮的小查询,它几乎正是我想要的。

非常感谢!

这是我的解决方案:

DECLARE @period integer = -12
DECLARE @startperiod date
DECLARE @endperiod date 
SET @startperiod = CAST(cast(year(DATEADD(month, @period, GETDATE())) AS varchar(4)) + '-' +
    cast(month(DATEADD(month, @period, GETDATE())) AS varchar(2)) + '-01' AS date)
SET @endperiod = CAST(cast(year(DATEADD(month, 0, GETDATE())) AS varchar(4)) + '-' +
    cast(month(DATEADD(month, 0, GETDATE())) AS varchar(2)) + '-01' AS datetime)

SELECT T1.ItemCode, T3.ItemName, 
       sum(case when datediff(month, T1.[docDate], GETDATE()) <= 12 then t1.quantity else 0 end) as month_12,
       sum(case when datediff(month, T1.[docDate], GETDATE()) <= 6 then t1.quantity else 0 end) as month_6,
       sum(case when datediff(month, T1.[docDate], GETDATE()) <= 3 then t1.quantity else 0 end) as month_3,
       sum(case when datediff(month, T1.[docDate], GETDATE()) = 1 then t1.quantity else 0 end) as month_1
FROM DLN1 T1 INNER JOIN ODLN T2 ON T1.docentry = T2.docentry INNER JOIN OITM T3 ON T1.ItemCode = T3.ItemCode
WHERE T1.[docDate] between CAST(@startperiod AS datetime) AND  DATEADD(second, -1, CAST(@endperiod AS datetime)) 
      AND T3.validFor = 'Y' AND T3.ItmsGrpCod = 100 --products / 102 raw materials
      AND T2.CANCELED = 'N'
GROUP BY T1.ItemCode, T3.ItemName
ORDER BY T3.ItemName ASC

@Gordon Linoff:“=”需要为“<=”,因为我希望销售量来自过去 12 个月的所有数量,而不是一年前一个月的数量。

再次感谢您的快速帮助!

转换需要调整将所有输入转换为单一数据类型,然后转换为日期数据类型 -

美式日期格式

declare @date date = cast( cast(month(DATEADD(month, @period, GETDATE())) as varchar(2)) + '-01-' 
        + cast(year(DATEADD(month, @period, GETDATE())) as varchar(4)) as date)

对于 ISO 日期格式

declare @date date = cast(cast(year(DATEADD(month, -1, GETDATE())) as varchar(4)) + '-' +
    cast(month(DATEADD(month, -1, GETDATE())) as varchar(2))
    + '-01' as date)

假设 ISO 格式是我的笨脑袋,一直不明白为什么 Mon DD YYYY 对于数据处理而不是表示是实用的

创建一个可以传递“要报告的月数”的函数 - 以减少主报告查询中的代码

create function MonthFirst (@period integer ) returns date
as begin
declare @returnperiod date 
set @returnperiod = cast(cast(year(DATEADD(month, @period, GETDATE())) as varchar(4)) + '-' +
    cast(month(DATEADD(month, @period, GETDATE())) as varchar(2))
    + '-01' as date)
 return @returnperiod
end

然后根据需要在查询中使用函数(例如)

select [3 Months Ago] = dbo.MonthFirst(-2)  -- 2020-12-01
select [Last Month] = dbo.MonthFirst(-1)  -- 2021-02-01
select [This Month] = dbo.MonthFirst(0)  -- 2021-03-01
select [Next Month] = dbo.MonthFirst(1)  -- 2021-04-01

这看起来像是一个简单的条件聚合示例:

select itemname, itemcode
       sum(case when datediff(month, date, 1) = 1 then quantity else 0 end) as month_1,
       sum(case when datediff(month, date, 1) <= 3 then quantity else 0 end) as month_3,
       sum(case when datediff(month, date, 1) <= 6 then quantity else 0 end) as month_6,
       sum(case when datediff(month, date, 1) <= 12 then quantity else 0 end) as month_12
from t
group by itemname, itemcode;

您的查询比您的描述所暗示的要复杂,但这应该会告诉您如何进行问题核心的计算。

请注意,datediff() 计算两个日期之间 边界 的数量,因此非常适合日历月。