连续年月总和

时间:2021-08-02 00:01:18

标签: sql sql-server tsql

我有一个包含每天和客户值的表格,我想按月列出所有客户组,但每一行都是过去 12 个月的客户:

示例

Customer   Date          Quantity
---------------------------------
cname-AA   2021/03/01    10
cname-AA   2021/03/02    20
cname-AA   2021/04/01    20
cname-AA   2021/04/02    20

cname-BB   2021/03/01    15
cname-BB   2021/03/02    25
cname-BB   2021/04/01    15
cname-BB   2021/04/02    35

预期结果:

Customer     2021-03    2021-04
-----------------------------------
cname-AA     30          40
cname-BB     40          50

我知道如何按客户和月份分组并过滤过去 12 个月。我的难点是将月份总数作为列返回。

4 个答案:

答案 0 :(得分:1)

如果您希望列按照您的描述进行结构化,实现这一目标的一种方法可能是使用 PIVOT 和动态 SQL。

PIVOT 函数允许您将行转换为列,而动态 SQL 提供了动态生成列名(例如,您示例中的月份的开始)的灵活性。特别是如果查询旨在聚合未知时间段内的数据。

这种方法还使数据能够驱动输出。这样您指定的日期越多,查询应按预期输出。

CREATE TABLE #CustomerTable (Customer VARCHAR(20), [Date] DATETIME, Quantity INT)
INSERT INTO #CustomerTable VALUES
('cname-AA','2021/03/01',10),('cname-AA','2021/03/02',20),('cname-AA','2021/04/01',20),('cname-AA','2021/04/02',20),
('cname-BB','2021/03/01',15),('cname-BB','2021/03/02',25),('cname-BB','2021/04/01',15),('cname-BB','2021/04/02',35)

-- stores dynamically generated months from dataset and the query to execute
DECLARE @Months AS NVARCHAR(MAX) = ''
DECLARE @Query  AS NVARCHAR(MAX) = ''

-- setup the months to PIVOT on
SELECT @Months = @Months + QUOTENAME(MonthStart) + ',' 
FROM (SELECT DISTINCT CONVERT(VARCHAR(7), ct.[Date], 126)  AS MonthStart
      FROM #CustomerTable ct) as tmp
SELECT @Months = SUBSTRING(@Months, 0, LEN(@Months))

SET @Query = '
SELECT *
FROM (
    SELECT ct.Customer,
           CONVERT(VARCHAR(7), ct.[Date], 126) AS MonthStart,
           ct.Quantity
    FROM #CustomerTable ct
    ) AS Src
    PIVOT (
        SUM(Quantity)
        FOR MonthStart IN (' + @Months + ')
    )   AS PivotTable';

EXECUTE(@Query)

DROP TABLE #CustomerTable

输出:

<头>
客户 2021-03 2021-04
cname-AA 30 40
cname-BB 40 50

答案 1 :(得分:0)

如果您只有日期,而没有时间,如示例中所示。此查询应该有效:

SELECT CUSTOMER, 
  SUM(CASE WHEN DATE BETWEEN '2021-03-01 00:00:00' AND '2021-03-31 00:00:00' THEN QUANTITY ELSE 0 END) MAR21,
  SUM(CASE WHEN DATE BETWEEN '2021-04-01 00:00:00' AND '2021-04-30 00:00:00' THEN QUANTITY ELSE 0 END) APR21
FROM TABLE1
GROUP BY CUSTOMER

这是小提琴: http://sqlfiddle.com/#!18/0da73c/4

要使用此功能,您的案例中需要更多列,每个月 10 列。

答案 2 :(得分:0)

如果我理解正确,您可以使用条件聚合:

select customer,
       sum(case when month(date) = 3 then quantity end) as mar,
       sum(case when month(date) = 4 then quantity end) as apr
from t
group by customer;

不清楚是否需要 where 子句将其限制在特定时间段内,例如:

where date >= '2021-03-01' and date < '2021-05-01'

答案 3 :(得分:0)

我知道这与您想要的输出不匹配,但我想向您展示一个更动态的替代方案,这意味着您不必在查询中对月份和年份进行“硬编码”。< /p>

WITH CTE AS
(
SELECT Customer, DATEPART(YEAR, DateTime2Field) As MyYear, DATEPART(Month, DateTime2Field) AS MyMonth,Quantity
FROM MyTable
)

SELECT Customer, CONCAT(MyYear, '-', MyMonth) AS [Year-Month], SUM(Quantity) AS SummedQuantiy
FROM CTE
GROUP BY Customer, MyYear, MyMonth
ORDER BY Customer, MyYear, MyMonth