Вопрос SQL: Получение Datediff в днях для каждой записи в группе - PullRequest
2 голосов
/ 30 января 2010

Учитывая эту таблицу:

alt text

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

Что нужно знать:

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

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

Отредактировано, чтобы добавить:

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

Ответы [ 3 ]

1 голос
/ 30 января 2010

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

Это будет работать только в 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 голосов
/ 30 января 2010

Сложный бит определяет предыдущий статус и помещает его в ту же строку, что и текущий статус. Было бы немного упрощено, если бы существовала корреляция между 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
0 голосов
/ 30 января 2010

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

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