【问题标题】:Add cumulative (running) totals to TSQL query (SQL Server 2008)? [duplicate]将累积(运行)总计添加到 TSQL 查询(SQL Server 2008)? [复制]
【发布时间】:2014-07-13 11:40:41
【问题描述】:

我有以下查询,显示特定日期范围内的每周总计:

declare @from_date datetime
declare @to_date datetime

SET @from_date = '2014-03-30';    
SET @to_date = '2014-08-10';    

SELECT DATEDIFF(week, 0, IDOC.Import_Date) Week,
    DATEADD(week, DATEDIFF(week, 0, IDOC.Import_Date), 0) 'From Date',
    DATEADD(week, DATEDIFF(week, 0, IDOC.Import_Date), 0) + 6 'End Date',
    COUNT(IDOC.IDOC_ID) 'Total'
FROM IDOC    
INNER JOIN dbo.File_Type FI     
        on IDOC.File_Type_ID = FI.File_Type_ID    
INNER JOIN  IDOC_Team_Assignment ITA    
    ON IDOC.IDOC_ID=ITA.IDOC_ID    
Where IDOC.Import_Date BETWEEN @from_date AND @to_date
GROUP BY DATEDIFF(week, 0, IDOC.Import_Date) 
ORDER BY DATEDIFF(week, 0, IDOC.Import_Date)

输出:

Week    | From Date      | End Date      | Total
--------------------------------------------------
5965    2014-04-28    2014-05-04        1
5967    2014-05-12    2014-05-18      1
5968    2014-05-19    2014-05-25      2

我想添加累计总计(运行总计)这是我想要完成的任务

 Week    | From Date      | End Date      | Total | Cummulative
    -------------------------------------------------------------
    5965    2014-04-28    2014-05-04        1       1
    5967    2014-05-12    2014-05-18      1         2
    5968    2014-05-19    2014-05-25      2         4

【问题讨论】:

  • stackoverflow.com/questions/860966/… 你想要一个累计,而不是累计。该链接向您展示了如何执行此操作;
  • 使用 SQL Server 2008 似乎不太直接,可能没有临时表?

标签: sql-server-2008 tsql aggregation


【解决方案1】:

xQbert 给你的链接向你展示了这个概念,但是当你的 select 中已经有另一个 count 时,它可能会有点混乱。

您需要删除您的 group by,并在您的两个 counts 上使用 over,限制一个只能超过 按你已经拥有的分组,第二个覆盖整个范围。

在这种情况下,您不能使用 rows unbound before,因为它会为每一行创建一个条目,而不是在现有结果集上构建。但是您确实需要在 overselect 的末尾保持 order by 同步。

而且你还需要添加distinct关键词。

SELECT DISTINCT
    DATEDIFF(week, 0, IDOC.Import_Date) Week,
    DATEADD(week, DATEDIFF(week, 0, IDOC.Import_Date), 0) 'From Date',
    DATEADD(week, DATEDIFF(week, 0, IDOC.Import_Date), 0) + 6 'End Date',
    COUNT(IDOC.IDOC_ID) OVER (PARTITION BY DATEDIFF(week, 0, IDOC.Import_Date)) 'Total',
    COUNT(IDOC.IDOC_ID) OVER (ORDER BY DATEDIFF(week, 0, IDOC.Import_Date)) 'Running Total'
FROM IDOC    
INNER JOIN dbo.File_Type FI     
        on IDOC.File_Type_ID = FI.File_Type_ID    
INNER JOIN  IDOC_Team_Assignment ITA    
    ON IDOC.IDOC_ID=ITA.IDOC_ID    
WHERE IDOC.Import_Date BETWEEN @from_date AND @to_date
ORDER BY DATEDIFF(week, 0, IDOC.Import_Date)

我无法在 SQL Server 2008 上对此进行测试,但我确实在 VS2013 中免费提供的任何内容中对其进行了测试,并且我知道它可以在 Oracle 中使用。值得一试。

这个是在 SQL Server 2008 R2 上测试的 - 我希望你不要急于获取这些数据...

SELECT
    DATEDIFF(week, 0, IDOC.Import_Date) Week,
    DATEADD(week, DATEDIFF(week, 0, IDOC.Import_Date), 0) 'From Date',
    DATEADD(week, DATEDIFF(week, 0, IDOC.Import_Date), 0) + 6 'End Date',
    COUNT(IDOC.IDOC_ID) 'Total',
    (
        SELECT
            COUNT(aIDOC.IDOC_ID)
        FROM
            IDOC aIDOC
        INNER JOIN dbo.File_Type aFI     
            ON aIDOC.File_Type_ID = aFI.File_Type_ID    
        INNER JOIN IDOC_Team_Assignment aITA    
            ON aIDOC.IDOC_ID=aITA.IDOC_ID    
        WHERE
            aIDOC.Import_Date BETWEEN @from_date AND @to_date
            AND DATEDIFF(week, 0, IDOC.Import_Date) <= DATEDIFF(week, 0, aIDOC.Import_Date)
    ) 'RunningTotal'
FROM
    IDOC
INNER JOIN dbo.File_Type FI     
    ON IDOC.File_Type_ID = FI.File_Type_ID    
INNER JOIN  IDOC_Team_Assignment ITA    
    ON IDOC.IDOC_ID=ITA.IDOC_ID    
WHERE
    IDOC.Import_Date BETWEEN @from_date AND @to_date
GROUP BY
    DATEDIFF(week, 0, IDOC.Import_Date) 
ORDER BY
    DATEDIFF(week, 0, IDOC.Import_Date)

现在我将其更改为在我看来更清晰的 CTE。

WITH CTE( WeekNbr, FromDate, EndDate, Total) AS (
    SELECT
        DATEDIFF(week, 0, IDOC.Import_Date) 'WeekNbr',
        DATEADD(week, DATEDIFF(week, 0, IDOC.Import_Date), 0) 'FromDate',
        DATEADD(week, DATEDIFF(week, 0, IDOC.Import_Date), 0) + 6 'EndDate',
        COUNT(IDOC.IDOC_ID) 'Total'
    FROM
        IDOC
    INNER JOIN dbo.File_Type FI     
        ON IDOC.File_Type_ID = FI.File_Type_ID    
    INNER JOIN  IDOC_Team_Assignment ITA    
        ON IDOC.IDOC_ID=ITA.IDOC_ID    
    WHERE
        IDOC.Import_Date BETWEEN @from_date AND @to_date
    GROUP BY
        DATEDIFF(week, 0, IDOC.Import_Date) 
)
SELECT
    A.WeekNbr,
    A.FromDate,
    A.EndDate,
    A.Total,
    (SELECT SUM(B.Total) FROM CTE B WHERE B.WeekNbr <= A.WeekNbr) 'RunningTotal'
FROM
    CTE A
ORDER BY
    A.WeekNbr

【讨论】:

  • 感谢你给我这个很好的例子。我需要弄清楚它为什么会出现:COUNT(IDOC.IDOC_ID) OVER (ORDER BY DATEDIFF(week, 0, IDOC.Import_Date)) 'Running Total'
  • 'order' 附近的语法不正确。
  • 这可能是您在 SQL Server 2008 中无法做到这一点,但微软表示它是 okay
  • 使用 order by with over,我的意思是
猜你喜欢
  • 2018-01-14
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-08-06
  • 1970-01-01
  • 1970-01-01
  • 2013-09-23
  • 2021-12-09
相关资源
最近更新 更多