it-swarm.com.de

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

Stellen Sie sich Helpdesk-Tickets vor, die zwischen Abteilungen übertragen werden. Wir möchten wissen, was die Abteilung am Ende des Tages für jedes Ticket für jeden Tag ist, an dem das Ticket geöffnet ist. Die Tabelle enthält die letzte Abteilung für jedes Ticket für jeden Tag, an dem es geöffnet ist und an dem sich die Abteilung ändert (einschließlich einer Zeile für das Datum, an dem das Ticket ursprünglich geöffnet wurde, und das Datum, an dem es 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 alle fehlenden Daten für jede TicketId mit der DepartmentId aus der vorherigen, nach Datum geordneten TicketAssigment-Zeile eingeben.

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

Es sieht so aus, als ob es nahe an dem liegt, was ich brauche, aber ich hatte nicht die Geduld, es zu Ende zu bringen, und die geschätzten Plankosten sind 6-stellig:

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?

13
Mark Freeman

Verwenden Sie LEAD(), um die nächste Zeile innerhalb der TicketId-Partition abzurufen. Schließen Sie sich dann einer Kalendertabelle an, um alle Daten zwischen zu erhalten.

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 von Möglichkeiten, um eine Kalendertabelle zu erhalten ...

14
Rob Farley

Dies ist eine schnelle Methode (ich habe weder Leistung noch 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

(enter image description here

4
Kin Shah