2016-11-14 4 views
1

Я пытаюсь понять, как сделать частичную сумму с условием на таблице.SQL: сумма в разделе с условием

Я эту таблицу:

CREATE TABLE [dbo].[test](
    [Id] [int] NOT NULL, 
    [part] [varchar](50) NULL, 
    [value] [int] NULL, 
    [TimeValue] [int] NULL, 
CONSTRAINT [PK_test] PRIMARY KEY CLUSTERED 
(
    [Id] ASC 
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY] 
) ON [PRIMARY] 

GO 
SET ANSI_PADDING OFF 
GO 
INSERT [dbo].[test] ([Id], [part], [value], [TimeValue]) VALUES (1, N'part1', 50, 15) 
GO 
INSERT [dbo].[test] ([Id], [part], [value], [TimeValue]) VALUES (2, N'part1', 8, 12) 
GO 
INSERT [dbo].[test] ([Id], [part], [value], [TimeValue]) VALUES (3, N'part1', 12, 9) 
GO 
INSERT [dbo].[test] ([Id], [part], [value], [TimeValue]) VALUES (4, N'part1', 10, 20) 
GO 
INSERT [dbo].[test] ([Id], [part], [value], [TimeValue]) VALUES (5, N'part2', 6, 4) 
GO 
INSERT [dbo].[test] ([Id], [part], [value], [TimeValue]) VALUES (6, N'part2', 9, 15) 
GO 

так

Id part value TimeValue 
1 part1 50  15 
2 part1 8  12 
3 part1 12  9 
4 part1 10  20 
5 part2 6  4 
6 part2 9  15 

и я Шоуда написать выберите, чтобы добавить столбец pSum AS INT с суммой на перегородке колонке part AS VARCHAR(50) на TimeValue AS INT<=of current row TimeValue

Я пишу это:

SELECT *, SUM(value) OVER (PARTITION BY part) AS pSum FROM test 

получение естественно:

Id part value TimeValue pSum 
1 part1 50   15  80 
2 part1 8   12  80 
3 part1 12   9  80 
4 part1 10   20  80 
5 part2 6   4  15 
6 part2 9   15  15 

, но это делает сумму на каждом целом разделе, я должен рассмотреть состояние TimeValue, чтобы получить это:

Id part value TimeValue pSum 
1 part1 50  15   70  (sum in part1 where TimeValue <= 15 : 12 + 8 + 50) 
2 part1 8  12   20  (sum in part1 where TimeValue <= 12 : 12 + 8) 
3 part1 12  9   12  (sum in part1 where TimeValue <= 9 : just 12) 
4 part1 10  20   80  (sum in part1 where TimeValue <= 20 : 12 + 8 + 50) 
5 part2 6  4   6  (sum in part2 where TimeValue <= 4 : just 6) 
6 part2 9  15   15  (sum in part2 where TimeValue <= 15 : 9 + 6) 

Я прочитал возможное решение для SQL 2012 год решение here:

SUM(value) OVER (PARTITION BY part ORDER BY TimeValue rows between unbounded preceding and current row) AS pSum 

, но я используя SQL 2008

Пожалуйста, помогите. Спасибо заранее.

ответ

2

В SQL Server 2008 нет действительно эффективного способа сделать это. Один метод использует outer apply:

select t.*, v.cumesum 
from test t outer apply 
    (select sum(t2.value) 
     from test t2 
     where t2.part = t.part and t2.timevalue <= t.timevalue 
    ) v(cumesum); 
+1

Учтите, что кто-то предлагает мне делать WHILE LOOP, но ваше решение действительно лучше. – user2595496

+1

@ user2595496 Это спорно. Для небольших наборов данных вы можете уйти с помощью 'CROSS/OUTER APPLY'. Для больших наборов данных вам лучше использовать курсор. Учтите, что метод, использующий 'APPLY', равен O (n^2), метод курсора (или цикла) - O (n). –

+0

@TT. , , , Метод, использующий 'APPLY', * не нужен * O (n^2). Кроме того, он может использовать индекс на 'test (part, timevalue)'. Тем не менее, при многих обстоятельствах использование цикла WHILE может быть лучше. Но он не основан на общем размере данных; он основан на максимальном количестве строк для данной 'part' - и наличии или отсутствии индексов. –

Смежные вопросы