2010-11-05 72 views
2

我有一张表,我们将其称为My_Table,它具有一个Created datetime列(在SQL Server中),我试图提取一份显示历史数据的报表行在一个特定的时间以月为单位到My_Table。现在我知道我可以显示有多少人添加每个月有:计算运行总计时出现错误(前几个时段累计)

SELECT YEAR(MT.Created), MONTH(MT.Created), COUNT(*) AS [Total Added] 
FROM My_Table MT 
GROUP BY YEAR(MT.Created), MONTH(MT.Created) 
ORDER BY YEAR(MT.Created), MONTH(MT.Created) 

这将返回类似:

YEAR MONTH  Total Added 
----------------------------- 
2009 01  25 
2009 02  127 
2009 03  241 

不过,我想通过获得列表大小给定的时间段(称之为您将要做的事;累计总和,历史报告):

YEAR MONTH  Total Size 
    ----------------------------- 
-- 2008 12  325 
    2009 01  350 
    2009 02  477 
    2009 03  718 

我想这一点:

Msg 8120, Level 16, State 1, Line 1 
Column 'My_Table .Created' is invalid in the select list because 
it is not contained in either an aggregate function or the GROUP BY clause. 

我只是知道我失去了一些东西很明显,但走开和回来后:

SELECT YEAR(MT.Created) 
    , MONTH(MT.Created) 
    ,(
    SELECT COUNT(*) FROM My_Table MT_int 
    WHERE MT_int.Created BETWEEN 
     CAST('2009/01/01' AS datetime) 
     AND DATEADD(s,-1,DATEADD(mm, DATEDIFF(m,0,MT.Created)+1,0)) 
     -- the last day of the current month 
     -- (Additional conditions can go here) 
    ) AS [Total added this month] 
FROM My_Table MT 
WHERE MT.Created > CAST('2009/01/01' AS datetime) 
GROUP BY YEAR(MT.Created), MONTH(MT.Created) 
ORDER BY YEAR(MT.Created), MONTH(MT.Created) 

但是,SQL Server与此错误响应并盯着它一段时间我不知所措。因此,如果有人会指出我在这里失踪(或指出我在做更好的方式)地球我会永远感激。

+1

您能举出样品数据吗?不确定你想要的月份总额是多少?还是一个跑步总数? – gbn 2010-11-05 15:46:52

+0

第2个月是否应包含第1个月的数据? – anivas 2010-11-05 15:51:39

+0

@anivas,@gbn是的,运行总数是我在找的。 – 2010-11-05 16:01:25

回答

4

“运行”,由行意味着行打破了这个。因此,一种方法是总结前几个月并将其添加到当前月份。要处理年份限制,您还需要每组最小/最大日期。 CROSS APPLY稍微有些RBAR,但是明确了(er?)发生了什么。

;WITH cTE AS 
(
SELECT 
    MIN(Created) AS FirstPerGroup, 
    MAX(Created) AS LastPerGroup, 
    YEAR(MT.Created) AS yr, MONTH(MT.Created) AS mth, COUNT(*) AS [Monthly Total Added] 
FROM MY_Table MT 
GROUP BY YEAR(MT.Created), MONTH(MT.Created) 
) 
SELECT 
    C1.yr, c1.mth, SUM(C1.[Monthly Total Added]), 
    ISNULL(PreviousTotal, 0) + SUM(C1.[Monthly Total Added]) AS RunningTotal 
FROM 
cTE c1 
CROSS APPLY 
(SELECT SUM([Monthly Total Added]) AS PreviousTotal FROM cTE c2 WHERE c2.LastPerGroup < C1.FirstPerGroup) foo 
GROUP BY 
    C1.yr, c1.mth, PreviousTotal 
ORDER BY 
    C1.yr, c1.mth 
+0

CTE比WHILE循环更高效吗? (我假设是...) – JNK 2010-11-05 16:19:51

+1

@JNK:一些好的索引会加快这一点,但WHILE循环对于较大的数据集可能更加一致。但是,它仍然是一个循环,所以在10年内,您将有120次聚合+ INSERT开销迭代构建输出结果集。总的来说,我会说这套方法会更好地运行 – gbn 2010-11-05 16:24:02

+0

+1 - 我学到了一些新东西。您可以推荐更多有关'CROSS APPLY'的优秀资源? Microsoft文档甚至不提示查询可以是表值函数。(和,*只*如果你有一刻......为什么我原来的查询抛出一个错误 - 我仍然不能看到我* *说*到SQL Server,只有我的意思* [如果这使得任何感觉在所有]]。 – 2010-11-05 18:13:11

2

你是2005年或以后,你可以用一个CTE

WITH CTE AS (
SELECT YEAR(MT.Created) as Yr 
    , MONTH(MT.Created) as Mth 
    ,( 
    SELECT COUNT(*) FROM My_Table MT_int 
    WHERE MT_int.Created BETWEEN 
     CAST('2009/01/01' AS datetime) 
     AND DATEADD(s,-1,DATEADD(mm, DATEDIFF(m,0,MT.Created)+1,0)) 
     -- the last day of the current month 
     -- (Additional conditions can go here) 
    ) AS Total 
FROM My_Table MT 
WHERE MT.Created > CAST('2009/01/01' AS datetime)) 

SELECT Yr, Mth, SUM(Total) as Total FROM CTE 
GROUP BY Yr, Mth 
ORDER BY Yr, Mth 
1

你可以采取汇总出最终的查询与这样的:

WITH CTE AS 
(SELECT DISTINCT YEAR(MT.Created) AS [Year] 
    , MONTH(MT.Created) AS [Month] 
FROM My_Table MT 
WHERE MT.Created > CAST('2009/01/01' AS datetime) 
) 
SELECT MT.[Year] 
    , MT.[Month] 
    ,(
    SELECT COUNT(*) FROM My_Table MT_int 
    WHERE MT_int.Created >= CAST('2009/01/01' AS datetime) 
     AND (YEAR(MT_int.Created) < MT.[Year] 
      OR (YEAR(MT_int.Created) = MT.[Year] 
       AND MONTH(MT_int.Created) <= MT.[Month]) 
      ) 
     -- the last day of the current month 
     -- (Additional conditions can go here) 
    ) AS [Total added this month] 
FROM CTE MT 
ORDER BY MT.[Year], MT.[Month] 

我认为应包括在同一年上一年或前一个月的所有过去的订单以及该月的所有订单。

0

称之为慢速方式,但可以通过函数来​​完成。不要这样做,如果My_Table很大。

Create Function [dbo].[RunningTotal](@Yr int, @Mnth int) 
Returns int 
AS 
BEGIN 
Declare @RC int 
Select @RC=count(*) 
From My_Table 
Where Year(Created)<@Yr or (Year(Created)[email protected] and Month(Created) <= @Mnth) 

Return @RC 
END