可以使用SQL计算时间段的累积数据吗?

时间:2014-03-03 23:08:33

标签: sql sql-server

我想知道是否可以仅使用SQL生成销售数据的运行总计或总计时间块。

假设我有一个记录销售情况和发生时间的简单表格。

ID | Timestamp           | Amount
1  | 2014-03-04 09:00:00 | 25.00
2  | 2014-03-04 09:02:25 | 15.00
3  | 2014-03-04 09:13:00 |  5.00
4  | 2014-03-04 09:16:11 | 17.50
5  | 2014-03-04 09:28:18 | 44.50
...

我可以使用以下查询轻松计算一天的总销售额:

SELECT sum(Amount) from Sales
WHERE Timestamp BETWEEN '2014-03-04 00:00:00' AND '2014-03-04 23:59:59'

但我想计算每个(比如说)15分钟内出售的金额,以获得如下结果:

08:45 |  0.00
09:00 | 45.00
09:15 | 62:00 
...

和每个(比如说)15分钟时段的累计运行总数,以产生如下结果:

08:45 |   0:00
09:00 |  40.00
09:15 | 107:00 
...

我可以编写一个简单的程序或使用电子表格来获得原始数据的这两个结果,但我想知道如何使用SQL来做到这一点。可能吗?如果是这样,怎么样?

编辑:如果可能,首选DB不可知解决方案。我目前使用SQL Server。

2 个答案:

答案 0 :(得分:0)

在SQL Server 2012中,您可以使用累积和窗口功能执行此操作。您还可以以接近在多个数据库中工作的方式获取时间段:

select timeslot,
       sum(amount) as amount,
       sum(sum(amount)) over (order by timeslot) as cumamount
from (select t.*,
             (cast('2014-03-04 00:00:00' as datetime) +
              cast( ("timestamp" - cast('2014-03-04 00:00:00' as datetime))*24*4 as int)/(24.0*4)
             ) as timeslot
      from table t
     ) t
where Timestamp between '2014-03-04 00:00:00' and '2014-03-04 23:59:59'
group by timeslot;

timeslot计算背后的想法是采用timestamp和某一天午夜之间的差异。这给出了两个日期之间的天数(分数)。然后将其乘以24小时和4乘15分钟,并给出自某个日期午夜起15分钟的间隔数。通过转换为整数并添加回原始日期来截断此值。这都是在子查询中完成的,因此可以重复计算。

这种方法适用于许多数据库,但确切表达可能会有一些细微差别。 datetime的格式将特定于数据库。

其余的只是使用累积和函数。如果你没有这个,那么你可以使用相关的子查询。

答案 1 :(得分:0)

第一次请求我没有sol。 (每个“Timeslot”类型的查询总计) 但我确实有第二次请求的sol。 (每个“时间段”的累计运行总数)

AS Gordon在SQL Server 2012中提到这一点要简单得多。 然而,因为我提供了一种可以在SQL 2005之后完成的旧方法。

此外,解决方案不是100%与数据库无关,而是更容易从SQL-SERVER转换为ORACLE或DB2或其他任何内容。

在进行实际查询之前,检查我创建的函数,当我给出两个Date Range时,只需给我一个TimeSlot值。 UFN to GET TIMESLOT Values

请注意,函数是由Slot Type以不同的粒度级别创建的。小时,分钟,秒等....你可以随意创建新的。

在下面的示例查询中,我选择了11秒的时间段。

检查结果。 Sample Output

    DECLARE @dt TABLE
    (
        RowID               INT IDENTITY    NOT NULL
        ,LastModified       DATETIME2(2)    NOT NULL
        ,Amount             INT NOT NULL DEFAULT 0
    )

    INSERT INTO @dt( LastModified, Amount )
                SELECT '2014-03-04 00:00:00.00', 10
    UNION ALL   SELECT '2014-03-04 00:00:05.00', 10
    UNION ALL   SELECT '2014-03-04 00:00:10.00', 10
    UNION ALL   SELECT '2014-03-04 00:00:15.00', 10
    UNION ALL   SELECT '2014-03-04 00:00:20.00', 10
    UNION ALL   SELECT '2014-03-04 00:00:25.00', 10
    UNION ALL   SELECT '2014-03-04 00:00:30.00', 10
    UNION ALL   SELECT '2014-03-04 00:00:35.00', 10
    UNION ALL   SELECT '2014-03-04 00:00:40.00', 10
    UNION ALL   SELECT '2014-03-04 00:00:45.00', 10
    UNION ALL   SELECT '2014-03-04 00:00:50.00', 10


    DECLARE @DatePart sysname
            ,@SlotValue INT
            ,@MinDt DATETIME2(2)
            ,@MaxDt DATETIME2(2)

    SET @SlotValue = 11
    SELECT  @MinDt=MIN(LastModified)
            ,@MaxDt=MAX(LastModified)
    FROM @dt

    ;WITH AllDt(RowID,timeslot,amount)
    AS
    (
        SELECT  CAST (ROW_NUMBER() OVER (ORDER BY COALESCE(t1.TimeSlot,t2.LastModified)) AS INT) RowID
                ,COALESCE(t1.TimeSlot,t2.LastModified)
                ,ISNULL(t2.Amount,0) AS Amount
        FROM dbo.ufn_utl_timeslotBySecond(@SlotValue,@MinDt,@MaxDt) t1
        FULL OUTER JOIN @dt t2
            ON t1.TimeSlot=t2.LastModified
    )
    ,
    RCTE1(RowID,timeslot,amount)
    AS
    (
        SELECT  RowID 
                ,timeslot
                ,Amount
        FROM AllDt
        WHERE RowID=1
        UNION ALL

        SELECT dt.RowID,dt.TimeSlot,CAST(dt.Amount+t3.amount AS INT) AS amount
        FROM ALLDt dt
        JOIN RCTE1 t3
            ON dt.RowID=t3.RowID+1
    )
    SELECT * 
    FROM RCTE1 
    ORDER BY TimeSlot