【问题标题】:T-SQL - Running total per projectT-SQL - 每个项目的运行总计
【发布时间】:2018-11-28 12:21:01
【问题描述】:

我有这个简化的表结构:

我需要生成一个汇总结果,对每个项目/期间的交易进行求和 - 并且每个项目都有一个运行总计。我添加了 TransactionCountInPeriod 列

如何编写查询以获得这样的结果:

就我的查询而言...我无法弄清楚如何计算per ProjectId的运行总数。

SELECT 
    prj.Id AS ProjectId,
    p.Id AS PeriodId,
    SUM(t.Amount) AS SumInPeriod--,
    --SUM(t.Amount) OVER (PARTITION BY prj.Id) AS RunningTotal
    --COUNT(t.*) AS TransactionCountInPeriod
FROM 
    Periods p
    CROSS JOIN Projects prj
    LEFT OUTER JOIN Transactions t ON p.Id = t.PeriodId
GROUP BY 
    prj.Id,
    p.Id
ORDER BY
    prj.Id,
    p.Id

架构和测试数据

CREATE TABLE [dbo].[Periods](
    [Id] [int] NOT NULL
)
GO

CREATE TABLE [dbo].[Projects](
    [Id] [int] IDENTITY(1,1) NOT NULL,
    [Name] [varchar](50) NOT NULL
)
GO

CREATE TABLE [dbo].[Transactions](
    [Id] [int] IDENTITY(1,1) NOT NULL,
    [ProjectId] [int] NOT NULL,
    [PeriodId] [int] NOT NULL,
    [Amount] [decimal](18, 0) NOT NULL
)

GO
INSERT [dbo].[Periods] ([Id]) VALUES (201801)
GO
INSERT [dbo].[Periods] ([Id]) VALUES (201802)
GO
INSERT [dbo].[Periods] ([Id]) VALUES (201803)
GO
INSERT [dbo].[Periods] ([Id]) VALUES (201804)
GO
INSERT [dbo].[Periods] ([Id]) VALUES (201805)
GO
SET IDENTITY_INSERT [dbo].[Projects] ON 
GO
INSERT [dbo].[Projects] ([Id], [Name]) VALUES (1, N'Alpha')
GO
INSERT [dbo].[Projects] ([Id], [Name]) VALUES (2, N'Beta')
GO
SET IDENTITY_INSERT [dbo].[Projects] OFF
GO
SET IDENTITY_INSERT [dbo].[Transactions] ON 
GO
INSERT [dbo].[Transactions] ([Id], [ProjectId], [PeriodId], [Amount]) VALUES (1, 1, 201801, CAST(100 AS Decimal(18, 0)))
GO
INSERT [dbo].[Transactions] ([Id], [ProjectId], [PeriodId], [Amount]) VALUES (2, 1, 201801, CAST(100 AS Decimal(18, 0)))
GO
INSERT [dbo].[Transactions] ([Id], [ProjectId], [PeriodId], [Amount]) VALUES (3, 1, 201802, CAST(100 AS Decimal(18, 0)))
GO
INSERT [dbo].[Transactions] ([Id], [ProjectId], [PeriodId], [Amount]) VALUES (4, 1, 201803, CAST(100 AS Decimal(18, 0)))
GO
INSERT [dbo].[Transactions] ([Id], [ProjectId], [PeriodId], [Amount]) VALUES (5, 1, 201803, CAST(100 AS Decimal(18, 0)))
GO
INSERT [dbo].[Transactions] ([Id], [ProjectId], [PeriodId], [Amount]) VALUES (6, 1, 201804, CAST(100 AS Decimal(18, 0)))
GO
INSERT [dbo].[Transactions] ([Id], [ProjectId], [PeriodId], [Amount]) VALUES (7, 2, 201801, CAST(100 AS Decimal(18, 0)))
GO
INSERT [dbo].[Transactions] ([Id], [ProjectId], [PeriodId], [Amount]) VALUES (8, 2, 201801, CAST(100 AS Decimal(18, 0)))
GO
INSERT [dbo].[Transactions] ([Id], [ProjectId], [PeriodId], [Amount]) VALUES (12, 2, 201804, CAST(100 AS Decimal(18, 0)))
GO
SET IDENTITY_INSERT [dbo].[Transactions] OFF
GO

(我会创建一个 sql fiddle,但是当我尝试时它总是崩溃......)

【问题讨论】:

    标签: tsql sql-server-2017


    【解决方案1】:

    您可以使用 SUM 窗口函数来计算运行总计。

    DECLARE @Periods TABLE(
        [Id] [int] NOT NULL
    )
    
    DECLARE @Projects TABLE(
        [Id] [int] NOT NULL,
        [Name] [varchar](50) NOT NULL
    )
    
    DECLARE @Transactions TABLE(
        [Id] [int] NOT NULL,
        [ProjectId] [int] NOT NULL,
        [PeriodId] [int] NOT NULL,
        [Amount] [decimal](18, 0) NOT NULL
    )
    
    INSERT @Periods ([Id]) VALUES (201801)
    INSERT @Periods ([Id]) VALUES (201802)
    INSERT @Periods ([Id]) VALUES (201803)
    INSERT @Periods ([Id]) VALUES (201804)
    INSERT @Periods ([Id]) VALUES (201805)
    INSERT @Projects ([Id], [Name]) VALUES (1, N'Alpha')
    INSERT @Projects ([Id], [Name]) VALUES (2, N'Beta')
    INSERT @Transactions ([Id], [ProjectId], [PeriodId], [Amount]) VALUES (1, 1, 201801, CAST(100 AS Decimal(18, 0)))
    INSERT @Transactions ([Id], [ProjectId], [PeriodId], [Amount]) VALUES (2, 1, 201801, CAST(100 AS Decimal(18, 0)))
    INSERT @Transactions ([Id], [ProjectId], [PeriodId], [Amount]) VALUES (3, 1, 201802, CAST(100 AS Decimal(18, 0)))
    INSERT @Transactions ([Id], [ProjectId], [PeriodId], [Amount]) VALUES (4, 1, 201803, CAST(100 AS Decimal(18, 0)))
    INSERT @Transactions ([Id], [ProjectId], [PeriodId], [Amount]) VALUES (5, 1, 201803, CAST(100 AS Decimal(18, 0)))
    INSERT @Transactions ([Id], [ProjectId], [PeriodId], [Amount]) VALUES (6, 1, 201804, CAST(100 AS Decimal(18, 0)))
    INSERT @Transactions ([Id], [ProjectId], [PeriodId], [Amount]) VALUES (7, 2, 201801, CAST(100 AS Decimal(18, 0)))
    INSERT @Transactions ([Id], [ProjectId], [PeriodId], [Amount]) VALUES (8, 2, 201801, CAST(100 AS Decimal(18, 0)))
    INSERT @Transactions ([Id], [ProjectId], [PeriodId], [Amount]) VALUES (12, 2, 201804, CAST(100 AS Decimal(18, 0)))
    
    select
        pr.Id as ProjectId
        , pe.Id as PeriodId
        , isnull(tr.SumAmount, 0) as SumInPeriod
        , isnull(sum(tr.SumAmount) over(partition by pr.Id order by pe.Id), 0) as RunningTotal
        , tr.TransactionsCount as TransactionCountInPeriod
    from @Projects pr
    cross join @Periods pe
    outer apply (select sum(t.Amount) as SumAmount, count(*) as TransactionsCount from @Transactions t where t.ProjectId = pr.Id and t.PeriodId = pe.Id)  tr
    order by ProjectId, PeriodId
    

    【讨论】:

      【解决方案2】:

      最简单的选择是使用sum...over
      你非常接近 - 但你不需要 group by 并且你需要将 order by 添加到 over 子句以获得运行总数 - 像这样:

      SELECT  pr.Id As ProjectId,
              pe.Id As PeriodId,
              SUM(Amount) OVER(PARTITION BY pe.Id, pr.Id) AS SumInPeriod,
              SUM(Amount) OVER(PARTITION BY pr.Id ORDER BY pe.Id) AS RunningTotal,
              COUNT(Amount) OVER(PARTITION BY pe.Id, pr.Id) TransactionCountInPeriod
      FROM (
          Periods pe
          CROSS JOIN projects as pr
          )
      LEFT JOIN Transactions tr 
          ON pe.Id = tr.PeriodId
          AND tr.ProjectId = pr.Id
      ORDER BY pr.id, pe.id 
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2011-05-28
        • 1970-01-01
        • 2019-03-19
        • 1970-01-01
        • 2014-10-29
        • 2021-08-14
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多