Inserisci le date mancanti con il valore dei dati della data popolata precedente per il gruppo


13

Picture ticket dell'help desk che vengono trasferiti tra i reparti. Vogliamo sapere quale sia il dipartimento alla fine della giornata per ogni biglietto per ogni giorno in cui il biglietto è aperto. La tabella contiene l'ultimo dipartimento per ogni biglietto per ogni giorno in cui è aperto in cui si verifica una modifica nel dipartimento (inclusa una riga per la data di apertura iniziale del biglietto e la data di chiusura). La tabella dei dati è simile alla seguente:

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

Ciò di cui ho bisogno è di inserire eventuali date mancanti per ciascun TicketId, utilizzando il DepartmentId della precedente riga TicketAssigment ordinata per Data.

Se ho righe TicketAssigment come questa:

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

Voglio questo risultato:

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

Sembra che potrebbe essere vicino a ciò di cui ho bisogno, ma non ho avuto la pazienza di lasciarlo finire e il costo del piano stimato ha 6 cifre:

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;

Ho il sospetto che ci sia un modo per farlo usando LAG e un telaio di una finestra, ma non l'ho ancora capito. Qual è un modo più efficiente per soddisfare il requisito?

Risposte:


14

Utilizzare LEAD()per ottenere la riga successiva all'interno della partizione TicketId. Quindi unisciti a una tabella del calendario per ottenere tutte le date tra.

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

Tutti i tipi di modi per ottenere una tabella del calendario ...


4

Questo è un modo rapido di fare (non ho testato le prestazioni o la scalabilità)

- crea una tabella del calendario

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

--- crea la tua tabella di test

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  )

--- Richiesta per ottenere l'output desiderato

;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

inserisci qui la descrizione dell'immagine


Grazie per questo! Il piano di esecuzione stimato mostra un set di risultati di 25 miliardi di righe, quindi rinegozeremo l'obbligo di segnalazione (che attualmente deve riportare ogni giorno per ogni biglietto dell'anno passato). Spero di poter mostrare l'ultimo DepartmentId per ogni biglietto e mostrare i dettagli di DepartmentId di giorno per un singolo biglietto selezionato su richiesta.
Mark Freeman,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.