如何在SQL Server中的特定日期范围或每个特定日期内对值进行分组

时间:2014-09-05 14:34:08

标签: sql sql-server date group-by sum

例如,表格为:

Customer   OrderDate   OrderAmt
--------   ----------  ---------
A1          20140101      920.00
A2          20140111      301.00
A2          20140123      530.00
A1          20140109      800.00
A3          20140110      500.00
A1          20140115      783.00
A3          20140217      500.00
A1          20140219     1650.00
A1          20140225      780.00
...
A3          20140901      637.00

我想将它们分组并计算每20天内的总和(OrderAmt),并按客户从20140101开始分组。

3 个答案:

答案 0 :(得分:0)

假设OrderDate是一个数字字段(不是varchar)。我还假设你将来不需要超过一年的时间。如果您想要显示间隙,请保持左连接,如果您不想要间隙,则将其设为内连接。 (您也可以将硬编码日期作为开始的变量,我将其保留为您提到的20140101。

with Numbers as 
(Select 0 as Num 
    UNION ALL 
 Select Num+1 
 FROM Numbers 
 WHERE Num+1<= 20
)
, DateList AS
(Select  Year(DateAdd(dd,20*(Num), Cast('2014-01-01' as date))) * 10000+Month(DateAdd(dd,20*(Num), Cast('2014-01-01' as date)))*100+Day(DateAdd(dd,20*(Num), Cast('2014-01-01' as date))) Groupingdatemin
, Year(DateAdd(dd,20*(Num+1)-1, Cast('2014-01-01' as date)))*10000+ MONTH(DateAdd(dd,20*(Num+1)-1, Cast('2014-01-01' as date)))*100+DAY(DateAdd(dd,20*(Num+1)-1, Cast('2014-01-01' as date))) Groupingdatemax
from Numbers
) 
select Customer, sum(orderamt), Groupingdatemin, Groupingdatemax from DateLIst d LEFT JOIN 
    <yourtable> t on t.orderdate between d.Groupingdatemin and d.Groupingdatemax
group by customer, Groupingdatemin, Groupingdatemax

答案 1 :(得分:0)

对于它的价值,您可以使用非常简单的DATEDIFF() / GROUP BY操作来完成您所描述的内容,如下所示:这是否实际上是您想要的可能是另一个问题。我怀疑DateBucket计算实际上可能是其他东西......

CREATE TABLE #tmpCustomer (Customer VARCHAR(2), OrderDate VARCHAR(10), OrderAmt DECIMAL(6,2))

INSERT INTO #tmpCustomer (Customer, OrderDate, OrderAmt)


SELECT 'A1',20140101,      920.00 UNION
SELECT 'A2',20140111,      301.00 UNION
SELECT 'A2',20140123,      530.00 UNION
SELECT 'A1',20140109,      800.00 UNION
SELECT 'A3',20140110,      500.00 UNION
SELECT 'A1',20140115,      783.00 UNION
SELECT 'A3',20140217,      500.00 UNION
SELECT 'A1',20140219,     1650.00 UNION
SELECT 'A1',20140225,      780.00 UNION
SELECT 'A3',20140901,      637.00


SELECT 
    Customer, 
    (DATEDIFF(day, '1/1/2014', CAST(OrderDate AS DATE)) / 20) + 1 AS DateBucket, 
    SUM(OrderAmt) SumOrderAmt
FROM #tmpCustomer
GROUP BY Customer, (DATEDIFF(day, '1/1/2014', CAST(OrderDate AS DATE)) / 20) + 1
ORDER BY Customer, DateBucket 

答案 2 :(得分:0)

你需要做两件事: (1)创建某种指南,保存'20天组'信息。递归CTE做得非常好,并且 (2)将varchar日期重新作为实际日期进行比较。

然后它只是将订单数据加入到该日期范围分组并对订单金额求和。

-------------------------
-- Here i'm just recreating your example
-------------------------
DECLARE @customerOrder TABLE (Customer varchar(2), OrderDate varchar(8), OrderAmt decimal(8,2))
INSERT INTO @customerOrder (Customer, OrderDate, OrderAmt)
VALUES
    ('A1', '20140101', 920.00),
    ('A2', '20140111', 301.00),
    ('A2', '20140123', 530.00),
    ('A1', '20140109', 800.00),
    ('A3', '20140110', 500.00),
    ('A1', '20140115', 783.00),
    ('A3', '20140217', 500.00),
    ('A1', '20140219', 1650.00),
    ('A1', '20140225', 780.00),
    ('A3', '20140901', 637.00)

-------------------------
-- Set up a table that lists off 20 day periods starting from 1/1/2014
-------------------------
DECLARE @startDate datetime, @endDate datetime; 

SET @startDate = {d N'2014-01-01'}; 
SET @endDate   = {d N'2014-12-31'}; 

WITH [dates] ([Sequence], [startDate], [maxExcludedDate]) AS 
   (SELECT 1 AS [Sequence] 
          ,@startDate AS [startDate] 
          ,DATEADD(d, 20, @startDate) AS [maxExcludedDate] 

    UNION ALL 
    SELECT Sequence + 1 AS Sequence 
          ,DATEADD(d, 20, [startDate]) AS [startDate] 
          ,DATEADD(d, 40, [startDate]) AS [maxExcludedDate]
    FROM [dates] 
    WHERE [startDate] < @endDate
) 
, dateFrame AS
( 
    SELECT 
          [startDate] 
          ,[maxExcludedDate]

    FROM [dates] 
)
-------------------------
-- Set up a table that holds the orderDates as actual dates
-------------------------
, castData AS
(
    SELECT
        cast(orderdate as datetime) castDate
        ,OrderAmt
    FROM @customerOrder
)

-------------------------
-- JOIN and sum.
-------------------------
SELECT
    [startDate]
    , Sum(OrderAmt) perodAmt
FROM
    dateFrame df

    left join castData cd
        on cd.castDate >= df.startDate
        and cd.castDate < df.maxExcludedDate
GROUP BY
    [startDate]

ORDER by
    [startDate]