MS SQL - 老化记录

时间:2016-11-30 23:02:48

标签: sql sql-server

请帮忙,因为我坚持这个!! :/

我在查询中选择了5列,最后2列是派生/计算的

Date | Account | Symbol | Type | User | AgeKEY | Age |    

其中KEY连接在一起(帐号+符号+类型+用户)

如何回顾历史1年并计算记录的年龄?年龄是AgeKey在历史记录中出现的连续工作日数

老化逻辑示例 -

11/3 KeyExists hence Age = 1

11/4 KeyExists hence Age = 2

11/7 KeyExists hence Age = 3 (note over weekend ages only by 1 day)

11/8 KeyDoesntExist

11/9 KeyExists hence Age = 1 (counter restarts from 1 if this happens)

1 个答案:

答案 0 :(得分:0)

使用T-SQL循环(它从选项卡表中读取数据并插入到tab_result):

create table tab 
(dt date, id int);

insert into tab values(DATEADD(day,-12,GETDATE()),1);
insert into tab values(DATEADD(day,-10,GETDATE()),1);
insert into tab values(DATEADD(day,-9,GETDATE()),1);
insert into tab values(DATEADD(day,-8,GETDATE()),1);
insert into tab values(DATEADD(day,-7,GETDATE()),3);
insert into tab values(DATEADD(day,-6,GETDATE()),3);
insert into tab values(DATEADD(day,-5,GETDATE()),1);
insert into tab values(DATEADD(day,-4,GETDATE()),1);
insert into tab values(DATEADD(day,-3,GETDATE()),1);

create table tab_result 
(dt date, id int, age int);

DECLARE @id INT, @dt date, @prevId INT=NULL, @prevDt date=NULL,  @age int

 DECLARE CurName CURSOR FAST_FORWARD READ_ONLY
 FOR
    SELECT  id,dt
    FROM    tab
    ORDER BY id,dt
 OPEN CurName


 FETCH NEXT FROM CurName INTO @id, @dt
 set @age=0;
 WHILE @@FETCH_STATUS = 0
    BEGIN
        if (@prevId<>@id or @prevDt <> DATEADD(day,-1, @dt))
                set @age=1;
            else
                set @age=@age+1;   
        insert into tab_result values (@dt, @id, @age )

        set @prevId=@id
        set @prevDt=@dt
        FETCH NEXT FROM CurName INTO @id, @dt

    END

 CLOSE CurName
 DEALLOCATE CurName

select * from tab_result order by id, dt;

使用普通的sql,它将类似于下面的内容(示例中的id是你的密钥):

create table tab 
(dt date, id int);

insert into tab values(DATEADD(day,-12,GETDATE()),1);
insert into tab values(DATEADD(day,-10,GETDATE()),1);
insert into tab values(DATEADD(day,-9,GETDATE()),1);
insert into tab values(DATEADD(day,-8,GETDATE()),1);
insert into tab values(DATEADD(day,-7,GETDATE()),3);
insert into tab values(DATEADD(day,-6,GETDATE()),3);
insert into tab values(DATEADD(day,-5,GETDATE()),1);
insert into tab values(DATEADD(day,-4,GETDATE()),1);
insert into tab values(DATEADD(day,-3,GETDATE()),1);

with x as ( 
select tab.dt,
    tab.id, 
    case when prev.dt is not null then  1 else 0 end  as exists_on_prev_day 
    from
    tab left outer join tab prev on (tab.id=prev.id and DATEADD(day,-1 , tab.dt)= prev.dt)
)
select id,dt, 
(select 
  -- count all records with the same id and date less or equal date of the given record
 count(*) from x x2 where x2.id=x.id and x2.dt<=x.dt
 -- (tricky part) we want to count only records between current record and last record without "previous" record (that is with exists_on_prev_day flag = 0)
  and not exists (select 1 from x x3 where x3.id=x2.id and x3.dt>x2.dt and x3.dt<=x.dt  and x3.exists_on_prev_day=0 )) age 
from x
order by id, dt;

结果:

    id  dt                  age
1   1   19.11.2016 00:00:00 1
2   1   21.11.2016 00:00:00 1
3   1   22.11.2016 00:00:00 2
4   1   23.11.2016 00:00:00 3
5   1   26.11.2016 00:00:00 1
6   1   27.11.2016 00:00:00 2
7   1   28.11.2016 00:00:00 3
8   3   24.11.2016 00:00:00 1
9   3   25.11.2016 00:00:00 2