是否可以编写基于列的运行总数分组的sql查询?
用一个例子来解释会更容易。假设我想每组最多得到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 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是否可以编写基于列的运行总数分组的sql查询?,sql,sql-server-2005,tsql,Sql,Sql Server 2005,Tsql,用一个例子来解释会更容易。假设我想每组最多得到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 A 2 A
我可以使用ROW_NUMBER来获取每组中的前X个记录,但是我的要求是获取每组的前X个项目,而不是X个记录。关于如何做到这一点,我的脑子一片空白。考虑到您评论中的澄清,您应该能够通过运行以下查询从您的帖子中生成第二个输出:
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
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
这是我到目前为止所拥有的。我知道它不完整,但是。。。这应该是一个很好的起点。我可以通过使用临时表和更新过程获得您的第二个输出:
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
也许有更好的办法,但这应该行得通
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
我已经更新了已接受的答案,并得到了您想要的结果。到目前为止,您有什么疑问?运行total questions的一个重要问题是了解您的物品是如何订购的。假设它们是按ID排序的是正确的吗?还是您有其他列,例如数据的排序日期?@dasblinkenlight它们是由首先创建记录的用户排序的一些用户的优先级高于其他用户,在创建记录的日期之前,我需要能够识别每个组中的实际行,因为它们一次处理一行,所以这不起作用。此外,需要以特定的方式对项目进行排序,以便将高优先级记录包括在前5项中group@Rachel-高优先级记录?你知道这个评论是你第一次提到这样的要求吗?编辑你的问题。添加更多的细节,更多的样本数据,尽量明确所有的要求。我的查询比我问题中的示例要复杂得多,尝试将其与您的代码示例结合起来是很有趣的。非常感谢您,这正是我所寻找的正确想法:+1,尽管我接受了Michal的答案,因为连接在性能上比子查询更好。谢谢:@Rachel这些天来,非玩具RDBMS引擎的查询优化器,比如SQL Server,可靠地为连接和相关子查询提供了相同的执行计划,当它们在语义上彼此相同时。我总是从一个更直接地表达我意图的查询开始,只有在查询分析器告诉我这是必要的时候才进行优化。
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