T-SQL - промежуточный итог по проекту - PullRequest
0 голосов
/ 28 ноября 2018

У меня есть упрощенная структура таблицы:

enter image description here

Мне нужно сгенерировать совокупный результат, суммируя транзакции по проекту / периоду - ииметь промежуточный итог на проект.Я добавил столбец TransactionCountInPeriod

Как мне написать запрос, чтобы получить такой результат:

enter image description here

Это настолько далеко, насколькоЯ получил с запросом ... Я не могу понять, как сделать промежуточный итог для 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

(Iсоздал бы скрипту sql, но он продолжает падать, когда я пытаюсь ...)

Ответы [ 2 ]

0 голосов
/ 28 ноября 2018

Самый простой вариант - использовать sum...over.
. Вы очень близки, но вам не нужна группа, и вам нужно добавить 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 
0 голосов
/ 28 ноября 2018

Вы можете использовать оконную функцию 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
...