Question

I need help in generating sequence number when group name changes in adjacent rows. I already tried DENSE RANK but it did not work.

Group  ||  Sequence Number 
========================
  A    ||        1     7/1/2012
  A    ||        2     7/2/2012
  A    ||        3     7/2/2012
  B    ||        1     7/3/2012
  B    ||        2     7/3/2012
  B    ||        3     7/3/2012
  A    ||        1     7/4/2012
  A    ||        2     7/5/2012
  A    ||        3     7/5/2012
  C    ||        1
  B    ||        1  
  B    ||        2  
  C    ||        1  
  C    ||        2

Thanks

Était-ce utile?

La solution

Here's a couple of solutions - one simple, one more complex but closer matching your question:

--if you want all As grouped first, then all Bs, etc
select *
, ROW_NUMBER() over (partition by [group] order by id) SequenceNumber
from demo

--if you want the more complex solution where the different groups of As are kept apart from one another
select id
, [group]
, ROW_NUMBER() over (partition by x.p order by x.id) sequenceNumber
from (
    select id
    , [group]
    , (
        select min(b.id)
        from demo b
        where b.[group] <> a.[group]
        and b.id > a.id
    ) p
    from demo a
) x
order by id

Code to setup / run the above sample:

create table demo 
(
    id bigint identity(1,1) not null primary key clustered
    , [group] nchar not null
)
go
insert demo 
select 'A'
union all select 'A'
union all select 'A'
union all select 'B'
union all select 'B'
union all select 'B'
union all select 'C'
union all select 'C'
union all select 'C'
union all select 'A' --in your example you seemed to alow a second group of As separate to the first
union all select 'A' 
union all select 'A' 
union all select 'A' 
union all select 'C'
go

Autres conseils

This should work, you can do a while loop.

declare @t table (
    id int identity primary key,
    yourgroup char,
    grouprank int
);
insert into @t (yourgroup)
select yourgroup
from yourtable;
declare @lastgroup char,
        @newrank int,
        @i int = (select MIN(id) from @t),
        @end int = (select MAX(id) from @t);
while @i <= @end begin
    if @lastgroup = (select yourgroup
                     from @t
                     where id = @i) begin
        set @newrank += 1;
    end else begin
        set @newrank = 1;
    end;

    select @lastgroup = yourgroup
    from @t
    where id = @i;

    update @t
    set grouprank = @newrank
    where id = @i;

    set @i += 1;
end;

select * from @t;

Sorry for the slow reply to your last comment; I've been at work/away for the start of the weekend. What you're after can be achieved based on my previous answer, but I suspect the code below would be much more efficient / readable. The drawback of the below code is that this does rely on the new SQL 2012 LAG and LEAD features.

You can read up on these features here: http://blog.sqlauthority.com/2011/11/15/sql-server-introduction-to-lead-and-lag-analytic-functions-introduced-in-sql-server-2012/

Info on SQL 2012 licensing here, should you choose to upgrade: http://www.microsoft.com/sqlserver/en/us/get-sql-server/how-to-buy.aspx

Obviously there are many reasons why upgrading may not be justifiable, but thought I'd provide this answer in case it's an option available to you / others looking for this solution:

--Sample Data Setup:

    if object_id('demo') is not null drop table demo
    go
    create table demo 
    (
        id bigint identity(1,1) not null primary key clustered
        , groupId nchar not null
        , startDate date not null constraint uk_demo_startDate unique 
    )
    go
    insert demo 
    select 'A', '2009-01-01'
    union all select 'A', '2009-01-02'
    union all select 'A', '2009-02-01'
    union all select 'B', '2009-03-01'
    union all select 'B', '2009-04-01'
    union all select 'B', '2009-05-01'
    union all select 'C', '2009-06-01'
    union all select 'C', '2009-07-01'
    union all select 'C', '2009-08-01'
    union all select 'A', '2009-09-01'
    union all select 'A', '2009-10-01'
    union all select 'A', '2009-11-01'
    union all select 'A', '2009-12-01'
    union all select 'C', '2010-01-01'
    union all select 'D', '2010-01-02'
    union all select 'D', '2010-01-03'
    union all select 'D', '2010-01-04'
    union all select 'E', '2010-01-05'
    union all select 'E', '2010-01-06'
    union all select 'D', '2010-01-07'
    union all select 'D', '2010-01-08'
    union all select 'E', '2010-01-09'
    union all select 'E', '2010-01-10'
    union all select 'D', '2011-01-01'
    union all select 'D', '2011-01-02'
    union all select 'E', '2012-01-01'
    union all select 'X', '2012-01-02'
    union all select 'D', '2012-01-03'
    go

--Actual Solution
    select *
    , noDays + noDaysAtStatusAtStart noDaysAtStatusAtEnd
    from
    (
        select id
        , groupId
        , startDate
        , noDays 
        ,   case
                when groupId = previousGroupId then lag(noDays,1) over (order by startDate)
                --when previousGroupId is null then 0 --covered by else
                else 0
            end noDaysAtStatusAtStart
        from
        (
            select id
            , startDate
            , groupId
            , endDate
            , previousGroupId
            , dateDiff(day,startDate,endDate) noDays
            from
            (
                select id
                , startDate
                , groupId 
                , lead(startDate,1) over (order by startDate) endDate
                , lag(groupId,1) over (order by startDate) previousGroupId
                from demo
            ) x
        ) y
    ) z
    order by z.startDate
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top