2012-08-02 66 views
1

當組名在相鄰行中更改時,我需要生成序號的幫助。我已經嘗試過密集排名但它沒有奏效。生成序列號比較TSQL中的相鄰行

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 

感謝

+0

A組發生兩次以上,是嗎? – iruvar 2012-08-02 23:43:19

+0

你使用了哪個數據庫? SQL 2012有一些時髦的功能可以幫助解決這個問題,但我猜測你已經不太可能使用該版本了? – JohnLBevan 2012-08-02 23:54:09

+0

我在SQL 2008 R2上 – sri 2012-08-03 00:14:47

回答

1

這裏有一對夫婦的解決方案 - 一個簡單的,一個更復雜,但是更匹配你的問題:

--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 

代碼設置/運行上面的示例:

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 
+0

感謝您的快速響應。我認爲以上更多的是基於A,B,C組演示表。如果該演示包含多個組,該怎麼辦?無論組的值/組數如何,上面的代碼都可以被推廣出來。再次感謝。 – sri 2012-08-03 00:55:26

+0

上面的代碼應該可以工作,而不管你的組有什麼值/數據類型。我不確定它的可擴展性/它是否是最好的解決方案。你能否提供更多關於你的要求的信息/你想要解決的問題。該解決方案是否需要單行SQL,或者我們可以使用存儲的procs /表值函數? PS。我對代碼進行了微調,以提高性能(將count(*)更改爲min(b.id))。 – JohnLBevan 2012-08-03 00:58:40

+0

這真棒,希望我能想到它! – pyrospade 2012-08-03 01:32:37

0

這應該工作,你可以做一個while循環。

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; 
+0

感謝您的支持。我用while循環嘗試了上面的解決方案,但是我將Grouprank作爲1用於所有行? 我在代碼中改變的唯一的東西是在這個語句中**從yourtable **中選擇yourgroup; 我將它更改爲**從組**中選擇deptname。 上面的代碼是否缺少任何循環或括號語句? – sri 2012-08-06 19:45:55

+0

我只是測試了代碼,它適用於我。什麼是deptname的數據類型和什麼是一些示例值? – pyrospade 2012-08-06 22:11:08

0

對不起,您對上一條評論的回覆緩慢;我在週末開始工作/離開。根據我之前的回答,你可以實現的是什麼,但是我懷疑下面的代碼會更有效率/可讀性。下面的代碼的缺點是這依賴於新的SQL 2012 LAG和LEAD特性。

你可以在這些功能的閱讀在這裏:在SQL http://blog.sqlauthority.com/2011/11/15/sql-server-introduction-to-lead-and-lag-analytic-functions-introduced-in-sql-server-2012/

信息2012的許可在這裏,你應該選擇升級:http://www.microsoft.com/sqlserver/en/us/get-sql-server/how-to-buy.aspx

顯然,有很多原因,升級未必是合理的,但思想我會提供這個答案,以防它可以爲您或其他人尋找這個解決方案提供一個選項:

--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