SQL查询基于序列
分组结果我有这样的一个表:SQL查询基于序列
ID Seq Amt
1 1 500
1 2 500
1 3 500
1 5 500
2 10 600
2 11 600
3 1 700
3 3 700
我想组连续的序列号为一行是这样的:
ID Start End TotalAmt
1 1 3 1500
1 5 5 500
2 10 11 1200
3 1 1 700
3 3 3 700
请帮助达到这个结果。
WITH numbered AS (
SELECT
ID, Seq, Amt,
SeqGroup = ROW_NUMBER() OVER (PARTITION BY ID ORDER BY Seq) - Seq
FROM atable
)
SELECT
ID,
Start = MIN(Seq),
[End] = MAX(Seq),
TotalAmt = SUM(Amt)
FROM numbered
GROUP BY ID, SeqGroup
ORDER BY ID, Start
;
+1花了我一会儿才弄清楚' - Seq'技巧,并验证(对于我自己)不会有任何碰撞,但OP不能要求比这更好的。 – 2011-02-23 08:39:44
+1我怀疑ROW_NUMBER(或RANK,...)会帮助我,但放弃了我的(更复杂,可能更慢)的解决方案。 – 2011-02-23 08:50:52
@Lieven:当我说这样的赞美时,请相信我,不需要任何正式的upvoting。 :)谢谢你,你很亲切!顺便说一句,你不应该删除你的答案。在我看来,另一个CTE演示从来没有太多,因为这是一个相当棘手的技术,这是最好的例子。我也没有注意到Martin或Quassnoi在这里的存在。 :) – 2011-02-23 08:51:37
请尝试以下查询。
select id, min(seq), max(seq), sum(amt) from table group by id
哎呀,对不起,这是错误的查询,因为你需要序列
这似乎很好地工作。 @breakingRows
将包含破坏id
和seq
序列的所有行(即如果id
改变或者如果seq
不比以前的seq
多1)。使用该表格,您可以在@temp
之内选择这样的序列的所有行。但是我必须补充说,由于所有的子查询,性能可能并不是那么好,但是你需要测试以确定。
declare @temp table (id int, seq int, amt int)
insert into @temp select 1, 1, 500
insert into @temp select 1, 2, 500
insert into @temp select 1, 3, 500
insert into @temp select 1, 5, 500
insert into @temp select 2, 10, 600
insert into @temp select 2, 11, 600
insert into @temp select 3, 1, 700
insert into @temp select 3, 3, 700
declare @breakingRows table (ctr int identity(1,1), id int, seq int)
insert into @breakingRows(id, seq)
select id, seq
from @temp t1
where not exists
(select 1 from @temp t2 where t1.id = t2.id and t1.seq - 1 = t2.seq)
order by id, seq
select br.id, br.seq as start,
isnull ((select top 1 seq from @temp t2
where id < (select id from @breakingRows br2 where br.ctr = br2.ctr - 1) or
(id = (select id from @breakingRows br2 where br.ctr = br2.ctr - 1) and
seq < (select seq from @breakingRows br2 where br.ctr = br2.ctr - 1))
order by id desc, seq desc),
br.seq)
as [end],
(select SUM(amt) from @temp t1 where t1.id = br.id and
t1.seq <
isnull((select seq from @breakingRows br2 where br.ctr = br2.ctr - 1 and br.id = br2.id),
(select max(seq) + 1 from @temp)) and
t1.seq >= br.seq)
from @breakingRows br
order by id, seq
感谢您的努力。解决方案非常完美!但我可以只标记一个答案作为最佳答案。 – Nagesh 2011-02-23 10:43:09
没问题。 Andriy的解决方案显然是最好的解决方案。 – 2011-02-23 12:11:37
嗯,有可能是一个更优雅的方式来做到这一点(的东西我有提示),但这里的一种方法,将如果你使用一个版本的SQL Server接受公共表表达式工作:
use Tempdb
go
create table [Test]
(
[id] int not null,
[Seq] int not null,
[Amt] int not null
)
insert into [Test] values
(1, 1, 500),
(1, 2, 500),
(1, 3, 500),
(1, 5, 500),
(2, 10, 600),
(2, 11, 600),
(3, 1, 700),
(3, 3, 700)
;with
lower_bound as (
select *
from Test
where not exists (
select *
from Test as t1
where t1.id = Test.id and t1.Seq = Test.Seq - 1
)
),
upper_bound as (
select *
from Test
where not exists (
select *
from Test as t1
where t1.id = Test.id and t1.Seq = Test.Seq + 1
)
),
bounds as (
select id, (select MAX(seq) from lower_bound where lower_bound.id = upper_bound.id and lower_bound.Seq <= upper_bound.Seq) as LBound, Seq as Ubound
from upper_bound
)
select Test.id, LBound As [Start], UBound As [End], SUM(Amt) As TotalAmt
from Test
join bounds
on Test.id = bounds.id
and Test.Seq between bounds.LBound and bounds.Ubound
group by Test.id, LBound, UBound
drop table [Test]
非常感谢您的努力。你的解决方案工作正常。 – Nagesh 2011-02-23 11:01:33
由于舍甫琴科已经贴金溶液,这里是使用UPDATE语句来得到一个临时表的结果我取,只是为了好玩。
declare @tmp table (
id int, seq int, amt money, start int, this int, total money,
primary key clustered(id, seq))
;
insert @tmp
select *, start=seq, this=seq, total=convert(money,amt)
from btable
;
declare @id int, @seq int, @start int, @amt money
update @tmp
set
@amt = total = case when id = @id and seq = @seq+1 then @amt+total else amt end,
@start = start = case when id = @id and seq = @seq+1 then @start else seq end,
@seq = this = seq,
@id = id = id
from @tmp
option (maxdop 1)
;
select id, start, max(this) [end], max(total) total
from @tmp
group by id, start
order by id, start
注:
- BTABLE:你的表名
- ID INT,SEQ INT,AMT钱:在你的表所需的列
它的工作原理,但这是一些新的SQL Server的东西给我。你已经设法发布一些有价值的东西,只要玩得开心,谢谢。 :) – 2011-02-23 09:39:02
'选择(maxdop 1)'有特定的原因吗?编辑:我想我只是想通了。你用'@ tmp'本身的数据更新'@ tmp'。多线程会干扰,对吗? – 2011-02-23 10:15:39
@Sem是的,因为这是一个脆弱的查询。在UPDATE查询中没有办法使用ORDER BY,所以AFAIK应该能够工作 - 但不能保证 - 如果我们按照需要的顺序进行聚类,并且强制maxdop 1。**我再次强调**(并且也投了票),Andriy的答案是黄金之一。 – RichardTheKiwi 2011-02-23 10:18:24
的SQL版本服务器? (id + seq)是唯一的吗? – RichardTheKiwi 2011-02-23 08:45:04