从总计中获取每月总计

时间:2013-08-08 14:30:12

标签: sql sql-server sql-server-2008

我在SQL Server 2008数据库中有一个表,其中有两列包含名为Hours和Starts的运行总计。另一列Date保存记录的日期。这个日期在任何一个月都是零星的,但是这个月的最后一个小时总是有记录。

例如:

ContainerID | Date             | Hours | Starts

1           | 2010-12-31 23:59 | 20    | 6
1           | 2011-01-15 00:59 | 23    | 6
1           | 2011-01-31 23:59 | 30    | 8

2           | 2010-12-31 23:59 | 14    | 2
2           | 2011-01-18 12:59 | 14    | 2
2           | 2011-01-31 23:59 | 19    | 3

如何查询表格以获取两个指定年份之间每个月的总小时数和开始时间? (在本例中为2011年和2013年。)我知道我需要从一个月的最后一条记录中取出值,然后用上个月最后一条记录中的值减去它。但是,我很难想出一个在SQL中执行此操作的好方法。

根据要求,以下是预期结果:

ContainerID | Date             | MonthlyHours | MonthlyStarts
1           | 2011-01-31 23:59 | 10           | 2
2           | 2011-01-31 23:59 | 5            | 1

2 个答案:

答案 0 :(得分:0)

试试这个:

SELECT  c1.ContainerID, 
        c1.Date, 
        c1.Hours-c3.Hours AS "MonthlyHours", 
        c1.Starts - c3.Starts AS "MonthlyStarts"
FROM Containers c1
LEFT OUTER JOIN Containers c2 ON
                                c1.ContainerID = c2.ContainerID
                            AND datediff(MONTH, c1.Date, c2.Date)=0
                            AND c2.Date > c1.Date
    LEFT OUTER JOIN Containers c3 ON
                                    c1.ContainerID = c3.ContainerID
                                AND datediff(MONTH, c1.Date, c3.Date)=-1
    LEFT OUTER JOIN Containers c4 ON
                                    c3.ContainerID = c4.ContainerID
                                AND datediff(MONTH, c3.Date, c4.Date)=0
                                AND c4.Date > c3.Date
    WHERE 
            c2.ContainerID is null
        AND c4.ContainerID is null
        AND c3.ContainerID is not null
ORDER BY c1.ContainerID, c1.Date

答案 1 :(得分:-1)

使用recursive CTE和一些'广告素材'加入条件,您可以为每个ContainterID获取下个月的值:

WITH CTE_PREP AS 
(
    --RN will be 1 for last row in each month for each container 
    --MonthRank will be sequential number for each subsequent month (to increment easier)
    SELECT 
        *
        ,ROW_NUMBER() OVER (PARTITION BY ContainerID, YEAR(Date), MONTH(DATE) ORDER BY Date DESC) RN
        ,DENSE_RANK() OVER (ORDER BY YEAR(Date),MONTH(Date)) MonthRank
    FROM Table1
)
, RCTE AS 
(
    --"Zero row", last row in decembar 2010 for each container
    SELECT *, Hours AS MonthlyHours, Starts AS MonthlyStarts
    FROM CTE_Prep
    WHERE YEAR(date) = 2010 AND MONTH(date) = 12 AND RN = 1 

    UNION ALL

    --for each next row just join on MonthRank + 1
    SELECT t.*, t.Hours - r.Hours, t.Starts - r.Starts
    FROM RCTE r
    INNER JOIN CTE_Prep t ON r.ContainerID = t.ContainerID AND r.MonthRank + 1 = t.MonthRank AND t.Rn = 1
)
SELECT ContainerID, Date, MonthlyHours, MonthlyStarts
FROM RCTE
WHERE Date >= '2011-01-01' --to eliminate "zero row"
ORDER BY ContainerID

SQLFiddle DEMO (我已在2月和3月添加了一些数据,以测试不同的月份)

Old version fiddle