2010-01-29 8 views
2

Учитывая эту таблицу:SQL Вопрос: Как DATEDIFF в истекшие дни для каждой записи в группе

alt text

Как я могу получить DATEDIFF в дни между каждой status_date для каждой группы ID_NUMBER? Другими словами, мне нужно найти количество прошедших дней для каждого статуса, предоставленного ID_Number.

Некоторые вещи, чтобы знать:

  • Все ID_NUMBER будет иметь received_date, которая должна быть самая ранняя дата для каждого ID_NUMBER (но приложение не обеспечивает)
  • Для каждого ID_NUMBER будет статус с соответствующий status_date, который является датой, когда ID_Number был присвоен этот конкретный статус.
  • В столбце состояния не всегда обязательно идти в том же порядке, каждый раз, когда (приложение не навязывает)
  • Все ID_NUMBER будет иметь closed_date, которая должна быть дата последней (но приложение не обеспечивает)

Образец вывода: Итак, для ID_Number 2001 первая дата (полученная_дата) - 2009-05-02, а следующая дата, с которой вы сталкиваетесь, имеет статус «open» и является 2009-05-02, поэтому прошедшие дни равны 0 . Переход на следующую встреченную дату - 2009-05-10 со статусом «инвестировать», а прошедшие дни - 8 с предыдущей даты. Следующая встречающая дата - 2009-07-11, и прошедшие дни - 62, отсчитываемые от предыдущей даты.

Edited добавить:

Можно ли иметь в прошедшие дни в конечном итоге в качестве столбца этой таблицы/представления? я забыл добавить, что это SQL Server 2000.

+0

Я добавил все столбцы в свой ответ, чтобы воспроизвести исходную таблицу с новым столбцом дней. Он равен нулю, когда нет значения closed_date. –

ответ

0

Некоторый пример вывод действительно поможет, но это предположение на то, что вы имеете в виду, если вы хотите, чтобы информация для каждой комбинации ID_NUMBER/Статуса:

select ID_Number, Status, EndDate - StartDate as DaysElapsed 
from (
    select ID_Number, Status, min(coalesce(received_date, status_date)) as StartDate, max(coalesce(closed_date, status_date)) as EndDate 
    from Table1 
    group by ID_Number, Status 
) a 
1

Я понимаю, что вам нужна разница между первым статусом_состояния и следующим статусом_состояния для одного и того же идентификатора и т. Д. До закрытого_дата.

Это будет работать только в SQL 2005 и выше.

;with test as (
    select 
     key, 
     id_number, 
     status, 
     received_date, 
     status_date, 
     closed_date, 
     row_number() over (partition by id order by status_date, key) as rownum 
    from @test 
    ) 
select 
    t1.key, 
    t1.id_number, 
    t1.status, 
    t1.status_date, 
    t1.received_date, 
    t1.closed_date, 
    datediff(d, case when t1.rownum = 1 
       then t1.received_date 
       else  
        case when t2.status_date is null 
         then t1.closed_date 
         else t2.status_date 
        end 
      end, 
      t1.status_date 
     ) as days 
from test t1 
left outer join test t2 
on t1.id = t2.id 
    and t2.rownum = t1.rownum - 1 

Это решение будет работать с SQL 2000, но я не уверен, насколько хорошо будет работать:

select *, 
    datediff(d, 
     case when prev_date is null 
      then closed_date 
      else prev_date 
     end, 
     status_date) 
from ( 
    select *, 
     isnull((select top 1 t2.status_date 
      from @test t2 
      where t1.id_number = t2.id_number 
      and t2.status_date < t1.status_date 
      order by t2.status_date desc 
     ),received_date) as prev_date 
    from @test t1 
) a 
order by id_number, status_date 

Примечание: Заменить @test таблицу с именем вашей таблицы.

+0

Я изменил результаты на основе выборочного вывода, добавленного в ваш вопрос. –

+0

Ugh. Похоже, это будет довольно уродливо реализовать в sql2000, который является информацией, которую я забыл добавить в мой оригинальный пост. – GregD

+0

@GregD: Столбец KEY всегда будет непрерывным для каждого ID_Number? –

0

Сложный бит определяет предыдущий статус и помещает его в ту же строку, что и текущий статус. Было бы немного упрощено, если бы была корреляция между Key и StatusDate (то есть Key(x) > Key(y) всегда подразумевает StatusDate(x) >= StatusDate(y)). К сожалению, похоже, это не так.

PS: Я принимаю Key - уникальный идентификатор на вашем столе; вы ничего не сказали, чтобы указать иначе.

SELECT Key, 
     ID_Number, 
     (
     SELECT TOP 1 Key 
     FROM StatusUpdates prev 
     WHERE (prev.ID_Number = cur.ID_Number) 
      AND ( (prev.StatusDate < cur.StatusDate) 
       OR ( prev.StatusDate = cur.StatusDate 
        AND prev.Key < cur.Key 
        ) 
       ) 
     ORDER BY StatusDate, Key /*Consider index on (ID_Number, StatusDate, Key)*/ 
     ) PrevKey 
FROM StatusUpdates cur 

После того как вы это в качестве основы, легко экстраполировать на любую другую информацию вам нужно от текущего или предыдущего StatusUpdate. Например.

SELECT c.*, 
     p.Status AS PrevStatus, 
     p.StatusDate AS PrevStatusDate, 
     DATEDIFF(d, c.StatusDate, p.StatusDate) AS DaysElapsed 
FROM (
     SELECT Key, 
       ID_Number, 
       Status, 
       SattusDate, 
       (
       SELECT TOP 1 Key 
       FROM StatusUpdates prev 
       WHERE (prev.ID_Number = cur.ID_Number) 
        AND ( (prev.StatusDate < cur.StatusDate) 
         OR ( prev.StatusDate = cur.StatusDate 
          AND prev.Key < cur.Key 
          ) 
         ) 
       ORDER BY StatusDate, Key 
       ) PrevKey 
     FROM StatusUpdates cur 
     ) c 
     JOIN StatusUpdates p ON 
      p.Key = c.PrevKey 

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

  • Нет связанных вопросов^_^