Complete las fechas faltantes con el valor de datos de la fecha poblada anterior para el grupo

13

Picture tickets de la mesa de ayuda que se transfieren entre departamentos. Queremos saber cuál es el departamento al final del día para cada boleto por cada día que el boleto está abierto. La tabla contiene el último departamento para cada ticket para cada día que está abierto en el que hay un cambio en el departamento (incluida una fila para la fecha en que el ticket se abrió inicialmente y la fecha en que se cerró). La tabla de datos se ve así:

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

Lo que necesito es completar las fechas faltantes para cada TicketId, usando el DepartmentId de la fila TicketAssigment anterior ordenada por Fecha.

Si tengo filas de TicketAssigment como esta:

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

Quiero esta salida:

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

Parece que podría estar cerca de lo que necesito, pero no he tenido la paciencia para dejar que termine, y el costo estimado del plan tiene 6 dígitos:

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;

Sospecho que hay una manera de hacer esto usando LAG y un marco de ventana, pero aún no lo he descubierto. ¿Cuál es una forma más eficiente de cumplir con el requisito?

Mark Freeman
fuente

Respuestas:

14

Use LEAD()para obtener la siguiente fila dentro de la partición TicketId. Luego, únete a una tabla de calendario para obtener todas las fechas intermedias.

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

Todo tipo de formas de obtener una tabla de calendario ...

Rob Farley
fuente
4

Esta es una forma rápida de hacerlo (no he probado el rendimiento o la escalabilidad)

- crear tabla de 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 tu tabla de prueba

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  )

--- Consulta para obtener la salida deseada

;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

ingrese la descripción de la imagen aquí

Kin Shah
fuente
¡Gracias por esto! El plan de ejecución estimado muestra un conjunto de resultados de 25 mil millones de filas, por lo que vamos a renegociar el requisito de informes (que actualmente es informar todos los días para cada ticket del año pasado). Espero que podamos mostrar el último ID de departamento para cada boleto y mostrar los detalles del ID de departamento por día para un boleto seleccionado a pedido.
Mark Freeman