SQL Query用于根据序列对结果进行分组

时间:2011-02-23 06:53:33

标签: sql sql-server

我有一张这样的表:

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

请帮助实现这一结果。

6 个答案:

答案 0 :(得分:21)

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 :(得分:1)

这似乎很好用。 @breakingRows将包含打破idseq序列的所有行(即,如果id更改或seq不比上一个{{1}更多1}})。使用该表,您可以在seq中选择此类序列的所有行。但是我必须补充说,由于所有子查询,性能可能不是那么好,但是你需要进行测试才能确定。

@temp

答案 2 :(得分:1)

好吧,也许有一种更优雅的方法可以做到这一点(有些东西暗示我有),但是如果您使用的是接受公用表表达式的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]

答案 3 :(得分:1)

由于Andriy已经发布了黄金解决方案,所以这是我使用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 money :表格中的预期列

答案 4 :(得分:0)

尝试以下查询。

select id, min(seq), max(seq), sum(amt) from table group by id

OOps,对不起,这是错误的查询,因为你需要序列

答案 5 :(得分:0)

SELECT Id, MIN(Seq) as Start, MAX(Seq) as End, SUM(Amount) as Total
FROM ( 
        SELECT t.*, Seq - ROW_NUMBER() OVER (PARTITION BY Id ORDER BY Seq) Rn
        FROM [Table] t
    ) as T
GROUP BY Id, Rn
ORDER BY Id, MIN(Seq)