Füllen Sie fehlende Daten mit dem Datenwert des vorherigen ausgefüllten Datums für die Gruppe aus

13

Picture Helpdesk-Tickets, die zwischen Abteilungen übertragen werden. Wir möchten wissen, was die Abteilung am Ende des Tages für jedes Ticket für jeden Tag, an dem das Ticket geöffnet ist, ist. Die Tabelle enthält die letzte Abteilung für jedes Ticket für jeden Tag, an dem es geöffnet ist, an dem es eine Änderung in der Abteilung gibt (einschließlich einer Zeile für das Datum, an dem das Ticket ursprünglich geöffnet und geschlossen wurde). Die Datentabelle sieht folgendermaßen aus:

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

Ich muss fehlende Daten für jede Ticket-ID unter Verwendung der Abteilungs-ID aus der vorherigen TicketAssigment-Zeile, sortiert nach Datum, ausfüllen.

Wenn ich TicketAssigment-Zeilen wie diese habe:

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

Ich möchte diese Ausgabe:

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

Das sieht so aus, als ob es in der Nähe dessen liegt, was ich brauche, aber ich hatte nicht die Geduld, es zu beenden, und die geschätzten Kosten des Plans bestehen aus 6 Ziffern:

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;

Ich vermute, dass es eine Möglichkeit gibt, dies mit LAG und einem Fensterrahmen zu tun, aber ich habe es nicht ganz herausgefunden. Was ist eine effizientere Möglichkeit, die Anforderung zu erfüllen?

Mark Freeman
quelle

Antworten:

14

Verwenden Sie LEAD()diese Option, um die nächste Zeile in der TicketId-Partition abzurufen. Verbinden Sie sich dann mit einer Kalendertabelle, um alle Daten zwischen diesen abzurufen.

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)
;

Alle Arten, einen Kalendertisch zu bekommen ...

Rob Farley
quelle
4

Dies ist eine schnelle Methode (ich habe weder die Leistung noch die Skalierbarkeit getestet)

- Kalendertabelle erstellen

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

--- Erstellen Sie Ihre Testtabelle

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  )

--- Abfrage, um die gewünschte Ausgabe zu erhalten

;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

Bildbeschreibung hier eingeben

Kin Shah
quelle
Danke dafür! Der geschätzte Ausführungsplan enthält eine Ergebnismenge von 25 Milliarden Zeilen. Daher werden wir die Berichtsanforderung neu aushandeln (die derzeit für jedes Ticket des vergangenen Jahres jeden Tag gemeldet wird). Ich hoffe, wir können die letzte DepartmentId für jedes Ticket anzeigen und auf Anfrage die Details der DepartmentId pro Tag für ein einzelnes ausgewähltes Ticket anzeigen.
Mark Freeman