如何在SQL Server中使用Group By运行小计

时间:2016-09-07 18:39:51

标签: sql sql-server

如何在SQL 2014中获取组的运行小计金额?

我有一张包含交易金额的表格。我需要总结一下,为每个项目和季度找到有数据的行,并且需要在每个项目中运行一个小计。对于每个新项目,运行总计需要重置为零。

这是我到目前为止所做的:

SELECT [ProjectId]
    , SUM( ActualAmount) AS PeriodAmount
    , SUM( ActualAmount) OVER (PARTITION BY ProjectId ORDER BY ProjectId,YearQuarter) 
        AS FairMarketValue

    FROM GLSnapshot 
    GROUP BY [ProjectId] , [YearQuarter]

我目前收到此错误:

Msg 8120,Level 16,State 1,Line 3

Column 'GLSnapshot.ActualAmount' is invalid in the 
select list because it is not contained in either an 
aggregate function or the GROUP BY clause.

示例数据:假设我有表格GLSnapshot的以下数据:

ProjectId, YearQuarter, ActualAmount
'A', '2015Q1' , 9000.00
'A', '2015Q1' ,  100.00
'A', '2015Q2' ,   50.00
'A', '2015Q3' ,   50.00
'A', '2015Q3' ,  200.00
'B', '2015Q1' ,80000.00

我应该得到

的以下结果
ProjectId, YearQuarter, PeriodAmount, FairMarketValue (Running Subtotal): 
'A', '2015Q1' , 9100.00 ,  9100.00
'A', '2015Q2' ,   50.00 ,  9150.00
'A', '2015Q3' ,  250.00 ,  9400.00
'B', '2015Q1' ,80000.00 , 80000.00

4 个答案:

答案 0 :(得分:2)

OLAP功能在汇总后计算,您无法使用ActualAmount,必须为SUM( ActualAmount)。并且无需按ProjectId订购,因为它已在PARTITION BY中。最后使用ROWS UNBOUNDED PRECEDING,否则默认为RANGE UNBOUNDED PRECEDING,这更昂贵,可能无法返回预期结果:

SELECT [ProjectId]
    , [YearQuarter]
    , SUM( ActualAmount) AS PeriodAmount
    , SUM( SUM( ActualAmount))
      OVER (PARTITION BY ProjectId
            ORDER BY YearQuarter
            ROWS UNBOUNDED PRECEDING) AS FairMarketValue

    FROM GLSnapshot 
    GROUP BY [ProjectId] , [YearQuarter]

答案 1 :(得分:0)

您可以使用之前无界限的行来提供总计

;with cte as (
select ProjectID, YearQuarter, ActualAmount
from GLSnapshot
) , cte2 as (
select ProjectID, YearQuarter, sum(ActualAmount) SumActualAmount  from cte Group by ProjectID, YearQuarter
) Select *, sum(SumActualAmount) over(partition by projectid order by projectid, yearquarter rows unbounded preceding) as RunningTotal from cte2

答案 2 :(得分:0)

试试这个:

CREATE TABLE #GLSnapshot (ProjectId VARCHAR(5), YearQuarter VARCHAR(6), ActualAmount NUMERIC(18,2))

INSERT INTO #GLSnapshot

SELECT 'A', '2015Q1' , 9000.00 UNION ALL
SELECT 'A', '2015Q1' ,  100.00 UNION ALL
SELECT 'A', '2015Q2' ,   50.00 UNION ALL
SELECT 'A', '2015Q3' ,   50.00 UNION ALL
SELECT 'A', '2015Q3' ,  200.00 UNION ALL
SELECT 'B', '2015Q1' ,80000.00



;WITH T
AS
(
    SELECT ROW_NUMBER() over(partition by ProjectId ORDER by YearQuarter) RN,
    ProjectId,YearQuarter,sum(ActualAmount) PeriodAmount
    FROM #GLSnapshot
    GROUP BY ProjectId,YearQuarter
)
SELECT T1.ProjectId,T1.YearQuarter,T1.PeriodAmount, SUM(T2.PeriodAmount) FairMarketValue 
FROM T T1
INNER JOIN T T2 ON T1.ProjectId = T2.ProjectId and T1.RN >= T2.RN
GROUP BY T1.ProjectId,T1.YearQuarter,T1.PeriodAmount

答案 3 :(得分:0)

您可以使用ROWS UNBOUNDED PRECEDING

尝试此查询
;with cte as (
select ProjectID, YearQuarter, ActualAmount
 from GLSnapshot
) , cte2 as (
select ProjectID, YearQuarter, sum(ActualAmount) SumActualAmount  from cte Group by ProjectID, YearQuarter
) Select *, sum(SumActualAmount) over(partition by projectid order by projectid, yearquarter rows unbounded preceding) as RunningTotal from cte2