2016-11-30 4 views
0

Пожалуйста, помогите, поскольку я застрял в этом! :/MS SQL - Отчеты о старениях

Я 5 колонок, которые я выбрать в запросе и последний 2 получены/вычисленные

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

где KEY конкатенируется (Account + Символ + тип + Пользователь)

Как я оглянуться назад на 1 год в историю и рассчитать возраст записи? Возраст является непрерывной # из рабочих дней, что AgeKey появляется в истории

Старение Logic Пример -

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

Что означает 11/3 KeyExists? –

+0

ваш вопрос непонятен, объясните логику ясно – sumit

+0

Это не совсем неясный вопрос ... Это проблема островов и пробелов в рабочие дни. Я предполагаю, что один из способов сделать это - это функция, которая получает минимальные/максимальные даты из таблицы, находит все рабочие дни между этими датами (а не выходные или праздничные дни, но вам нужна таблица, полная публики даты отпуска для этого), затем левые присоединяются к оригинальной таблице и сравнивают. – ZLK

ответ

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 @[email protected]+1; 
     insert into tab_result values (@dt, @id, @age) 

     set @[email protected] 
     set @[email protected] 
     FETCH NEXT FROM CurName INTO @id, @dt 

    END 

CLOSE CurName 
DEALLOCATE CurName 

select * from tab_result order by id, dt; 

с простой SQL это будет что-то вроде ниже (идентификатор в примере является ключом):

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

Спасибо, давайте попробуем !! –

+0

Запрос выполняется очень долго и не возвращает никаких результатов с моими столбцами .. это потому, что я создаю ключ на лету? –

+0

yep. Вы можете попытаться оптимизировать вышеуказанный запрос, создав временную таблицу, но это, вероятно, не лучшее решение для вашей проблемы, поскольку оно должно подсчитывать все записи перед данными. Событие с соответствующими индексами будет медленным. Скорее всего, это было бы намного проще, просто используя T-SQL и вычислив возраст в цикле. – arturro

Смежные вопросы