Uzupełnij brakujące daty wartością danych z poprzedniej wypełnionej daty dla grupy

13

Zdjęcie pomocy technicznej, która jest przenoszona między oddziałami. Chcemy wiedzieć, jaki jest departament na koniec dnia dla każdego biletu na każdy dzień, w którym bilet jest otwarty. Tabela zawiera ostatni dział dla każdego biletu dla każdego dnia, w którym jest otwarty, w którym następuje zmiana w dziale (w tym wiersz dotyczący daty pierwszego otwarcia biletu i daty jego zamknięcia). Tabela danych wygląda następująco:

CREATE TABLE TicketAssigment (
    TicketId     INT NOT NULL,
    AssignedDate DATE NOT NULL,
    DepartmentId INT NOT NULL);

Potrzebuję uzupełnić brakujące daty dla każdego TicketId, używając DepartmentId z poprzedniego wiersza TicketAssigment uporządkowanego według daty.

Jeśli mam takie wiersze TicketAssigment:

1, '1/1/2016', 123 -- Opened
1, '1,4,2016', 456 -- Transferred and closed
2, '1/1/2016', 25  -- Opened
2, '1/2/2016', 52  -- Transferred
2, '1/4/2016', 25  -- Transferred and closed

Chcę tego wyniku:

1, '1/1/2016', 123
1, '1/2/2016', 123
1, '1/3/2016', 123
1, '1/4/2016', 456
2, '1/1/2016', 25
2, '1/2/2016', 52
2, '1/3/2016', 52
2, '1/4/2016', 25

Wygląda na to, że może być blisko tego, czego potrzebuję, ale nie miałem cierpliwości, aby to zakończyć, a szacowany koszt planu ma 6 cyfr:

SELECT  l.TicketId, c.Date, MIN(l.DepartmentId)
FROM    dbo.Calendar c 
        OUTER APPLY (SELECT TOP 1 TicketId, DepartmentId FROM TicketAssigment WHERE AssignedDate <= c.Date ORDER BY AssignedDate DESC) l
WHERE   c.Date <= (SELECT MAX(AssignedDate) FROM TicketAssigment)
GROUP   BY l.TicketId, c.Date
ORDER   BY l.TicketId, c.Date;

Podejrzewam, że można to zrobić za pomocą LGD i ramy okiennej, ale nie do końca to rozgryzłem. Jaki jest bardziej skuteczny sposób spełnienia tego wymagania?

Mark Freeman
źródło

Odpowiedzi:

14

Służy LEAD()do uzyskania następnego wiersza w partycji TicketId. Następnie dołącz do tabeli kalendarza, aby uzyskać wszystkie daty między.

WITH TAwithnext AS
(SELECT *, LEAD(AssignmentDate) OVER (PARTITION BY TicketID ORDER BY AssignmentDate) AS NextAssignmentDate
 FROM TicketAssignment
)
SELECT t.TicketID, c.Date, t.DepartmentID
FROM dbo.Calendar c
JOIN TAwithnext t
    ON c.Date BETWEEN t.AssignmentDate AND ISNULL(DATEADD(day,-1,t.NextAssignmentDate),t.AssignmentDate)
;

Wszystkie rodzaje sposobów uzyskania tabeli kalendarza ...

Rob Farley
źródło
4

Jest to szybki sposób (nie testowałem wydajności ani skalowalności)

- utwórz tabelę kalendarza

-- borrowed from @Aaron's post http://sqlperformance.com/2013/01/t-sql-queries/generate-a-set-3 
CREATE TABLE dbo.Calendar(d DATE PRIMARY KEY);

INSERT dbo.Calendar(d) SELECT TOP (365)
 DATEADD(DAY, ROW_NUMBER() OVER (ORDER BY number)-1, '20160101')
 FROM [master].dbo.spt_values
 WHERE [type] = N'P' ORDER BY number;

--- utwórz tabelę testową

CREATE TABLE dbo.TicketAssigment (
    TicketId     INT NOT NULL,
    AssignedDate DATE NOT NULL,
    DepartmentId INT NOT NULL);

--  truncate table dbo.TicketAssigment;

insert into dbo.TicketAssigment values (1   ,   '1-1-2016'  ,   123 )
insert into dbo.TicketAssigment values (1   ,   '1-4-2016'  ,   456 )
insert into dbo.TicketAssigment values (2   ,   '1-1-2016'  ,   25  )
insert into dbo.TicketAssigment values (2   ,   '1-2-2016'  ,   52  )
insert into dbo.TicketAssigment values (2   ,   '1-4-2016'  ,   25  )

--- Zapytanie, aby uzyskać pożądany wynik

;with Cte as
(
  select TicketID, 
         min(AssignedDate) minAD, -- This is the min date
         max(AssignedDate) maxAD  -- This is the max date
  from TicketAssigment
  group by TicketID
)
select Cte.TicketID,
       c.d as AssignedDate,

       ( -- Get DeptID
       select top(1) T.departmentID
       from dbo.TicketAssigment as T
       where T.TicketID = cte.TicketID and
             T.AssignedDate <= c.d
       order by T.AssignedDate desc
       ) as DepartmentID
from Cte
  left outer join dbo.Calendar as c
      on c.d between Cte.minAD and Cte.maxAD
    order by Cte.TicketID

wprowadź opis zdjęcia tutaj

Kin Shah
źródło
Dzięki za to! Szacowany plan wykonania pokazuje zestaw wyników wynoszący 25 miliardów wierszy, więc będziemy renegocjować wymóg raportowania (który jest obecnie raportowany każdego dnia dla każdego biletu w ubiegłym roku). Mam nadzieję, że możemy pokazać ostatni DepartmentId dla każdego biletu i pokazać szczegóły DepartmentId według dnia dla jednego wybranego biletu na żądanie.
Mark Freeman