Можно ли написать SQL-запрос, сгруппированный на основе промежуточного итога столбца? - PullRequest
3 голосов
/ 03 января 2012

Было бы проще объяснить на примере. Предположим, я хотел получить не более 5 предметов в группе.

Мой ввод будет выглядеть так:

Item    Count
A        2
A        3
A        3
B        4
B        4
B        5
C        1

И мой желаемый результат будет выглядеть так:

Item     Count
A        5
A>5      3
B        4
B>5      9
C        1

Альтернативный вывод, с которым я мог бы работать, был бы

Item    Count    RunningTotal
A       2        2
A       3        5
A       3        8
B       4        4
B       4        8
B       5        13
C       1        1

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

Ответы [ 6 ]

5 голосов
/ 04 января 2012
declare @yourTable table (item char(1), [count] int)

insert into @yourTable
select 'A', 2 union all
select 'A', 3 union all
select 'A', 3 union all
select 'B', 4 union all
select 'B', 4 union all
select 'B', 5 union all
select 'C', 1

;with cte(item, count, row) as (
    select *, row_number() over ( partition by item order by item, [count]) 
    from @yourTable
)
select t1.Item, t1.Count, sum(t2.count) as RunningTotal from cte t1
join cte t2 on t1.item = t2.item and t2.row <= t1.row
group by t1.item, t1.count, t1.row

Результат:

Item Count       RunningTotal
---- ----------- ------------
A    2           2
A    3           5
A    3           8
B    4           4
B    4           8
B    5           13
C    1           1
1 голос
/ 04 января 2012
declare @yourTable table (item char(1), [count] int)

insert into @yourTable
select 'A', 2 union all
select 'A', 3 union all
select 'A', 3 union all
select 'B', 4 union all
select 'B', 4 union all
select 'B', 5 union all
select 'C', 1

;with cte(item, count, row) as (
    select *, row_number() over ( partition by item order by item, [count]) 
    from @yourTable
)

select t1.row, t1.Item, t1.Count, sum(t2.count) as RunningTotal
into #RunTotal
from cte t1
join cte t2 on t1.item = t2.item and t2.row <= t1.row
group by t1.item, t1.count, t1.row


alter table #RunTotal
add GrandTotal int

update rt
set GrandTotal = gt.Total
from #RunTotal rt
left join ( 
    select Item, sum(Count) Total
    from #RunTotal rt
    group by Item) gt
on rt.Item = gt.Item


select Item, max(RunningTotal)
from #RunTotal
where RunningTotal <= 5
group by Item

union

select a.Item + '>5', total - five
from (
    select Item, max(GrandTotal) total
    from #RunTotal
    where GrandTotal > 5
    group by Item
) a
left join (
    select Item, max(RunningTotal) five
    from #RunTotal
    where RunningTotal <= 5
    group by Item
) b
    on a.Item = b.Item

Я обновил принятый ответ и получил желаемый результат.

1 голос
/ 04 января 2012

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

select t.Item
,   t.Count
,   (select sum(tt.count)
    from mytable tt
    where t.item=tt.item and (tt.creating_user_priority < t.creating_user_priority or
        ( tt.creating_user_priority = t.creating_user_priority and tt.created_date < t.createdDate))
    ) as RunningTotal
from mytable t
0 голосов
/ 04 января 2012

Я могу получить ваш второй вывод, используя временную таблицу и проход обновления:

DECLARE @Data TABLE
(
    ID INT IDENTITY(1,1) PRIMARY KEY
    ,Value VARCHAR(5)
    ,Number INT
    ,Total INT
)
INSERT INTO @Data (Value, Number) VALUES ('A',2)
INSERT INTO @Data (Value, Number) VALUES ('A',3)
INSERT INTO @Data (Value, Number) VALUES ('A',3)
INSERT INTO @Data (Value, Number) VALUES ('B',4)
INSERT INTO @Data (Value, Number) VALUES ('B',4)
INSERT INTO @Data (Value, Number) VALUES ('B',5)
INSERT INTO @Data (Value, Number) VALUES ('C',1)

DECLARE 
    @Value VARCHAR(5)
    ,@Count INT

UPDATE @Data
SET
    @Count = Total = CASE WHEN Value = @Value THEN Number + @Count ELSE Number END
    ,@Value = Value
FROM @Data AS D

SELECT 
    Value
    ,Number
    ,Total 
FROM @Data

Возможно, есть лучшие способы, но это должно сработать.

0 голосов
/ 04 января 2012
select 'A' as Name, 2 as Cnt
into #tmp
union all select 'A',3
union all select 'A',3
union all select 'B',4
union all select 'B',4
union all select 'B',5
union all select 'C',1

select Name, case when sum(cnt) > 5 then 5 else sum(cnt) end Cnt
from #tmp
group by Name
union 
select Name+'>5', sum(cnt)-5 Cnt
from #tmp
group by Name
having sum(cnt) > 5

Вот что у меня так далеко.Я знаю, что это не завершено, но ... это должно быть хорошей отправной точкой.

0 голосов
/ 03 января 2012
SELECT Item, SUM(Count)
FROM mytable t
GROUP BY Item
HAVING SUM(Count) <=5 

UNION  

SELECT Item,  5
FROM mytable t
GROUP BY Item
HAVING SUM(Count) >5 

UNION  


SELECT t2.Item + '>5', Sum(t2.Count) - 5
FROM mytable t2
GOUP BY Item
HAVING SUM(Count) > 5

ORDER BY 1, 2
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...