Ошибка при расчете промежуточного итога (кумулятивно за предыдущие периоды) - PullRequest
2 голосов
/ 05 ноября 2010

У меня есть таблица, назовем ее My_Table, в которой есть Created столбец даты и времени (в 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

Я пытаюсь это:

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 отвечает этой ошибкой:

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.

Я просто знаю Я упускаю что-то очевидное, но после того, как ушел и пришелназад и глядя на него некоторое время, я в растерянности.Поэтому, если бы кто-то был так любезен, чтобы указать на то, что на земле я здесь упускаю (или укажите мне лучший способ сделать это), я был бы вечно благодарен.

Ответы [ 4 ]

4 голосов
/ 05 ноября 2010

«Бег» подразумевает строку за строкой. Таким образом, одним из способов является суммирование предыдущих месяцев и добавление его к текущему месяцу. Чтобы справиться с границами года, вы также можете выбрать минимальную / максимальную дату для каждой группы. CROSS APPLY немного RBAR, но проясняет (э?), Что происходит.

;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
2 голосов
/ 05 ноября 2010

Вы на 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 голос
/ 05 ноября 2010

Вы можете вывести совокупность из окончательного запроса примерно так:

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 голосов
/ 05 ноября 2010

Называйте это медленным путем, но вы можете сделать это с помощью функции. Не делайте этого, если 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)=@Yr and Month(Created) <= @Mnth)

 Return @RC
END
...