Dados los siguientes datos:
create table #histories
(
username varchar(10),
account varchar(10),
assigned date
);
insert into #histories
values
('PHIL','ACCOUNT1','2017-01-04'),
('PETER','ACCOUNT1','2017-01-15'),
('DAVE','ACCOUNT1','2017-03-04'),
('ANDY','ACCOUNT1','2017-05-06'),
('DAVE','ACCOUNT1','2017-05-07'),
('FRED','ACCOUNT1','2017-05-08'),
('JAMES','ACCOUNT1','2017-08-05'),
('DAVE','ACCOUNT2','2017-01-02'),
('PHIL','ACCOUNT2','2017-01-18'),
('JOSH','ACCOUNT2','2017-04-08'),
('JAMES','ACCOUNT2','2017-04-09'),
('DAVE','ACCOUNT2','2017-05-06'),
('PHIL','ACCOUNT2','2017-05-07') ;
... que representa cuándo un usuario determinado fue asignado a una cuenta.
Estoy buscando establecer quién era el propietario de una cuenta determinada el último día de cada mes (la fecha asignada es la fecha en que la cuenta transfirió la propiedad), con cualquier fin de mes faltante poblado (posiblemente creado a partir de una práctica dates
tabla que tengo disponible, con columnas útiles DateKey
, Date
y LastDayOfMonth
, [cortesía de @AaronBertrand]) 1 .
Los resultados deseados serían:
PETER, ACCOUNT1, 2017-01-31
PETER, ACCOUNT1, 2017-02-28
DAVE, ACCOUNT1, 2017-03-31
DAVE, ACCOUNT1, 2017-04-30
FRED, ACCOUNT1, 2017-05-31
FRED, ACCOUNT1, 2017-06-30
FRED, ACCOUNT1, 2017-07-31
JAMES, ACCOUNT1, 2017-08-31
PHIL, ACCOUNT2, 2017-01-31
PHIL, ACCOUNT2, 2017-02-28
PHIL, ACCOUNT2, 2017-03-31
JAMES, ACCOUNT2, 2017-04-30
PHIL, ACCOUNT2, 2017-05-31
Hacer la parte inicial de esto con una función de ventana es trivial, es agregar las filas "faltantes" con las que estoy luchando.
2017-05
porque la tenía puesta2017-05-07
y no había un titular posterior?Respuestas:
Un enfoque para este problema es hacer lo siguiente:
LEAD
en SQL Server 2008. Puede usarAPPLY
o una consulta para esto.Modifiqué un poco sus datos de prueba para hacer que los resultados sean deterministas. También se agregó un índice:
Aquí está la tabla de dimensiones de fecha más perezosa de todos los tiempos:
Para el paso 1, hay muchas formas de emular
LEAD
. Aquí hay un método:Para el paso 2, necesitamos cambiar los valores NULL a otra cosa. Desea incluir el último mes para cada cuenta, por lo que es suficiente agregar un mes a la fecha de inicio:
Para el paso 3, podemos unirnos a la tabla de dimensiones de fecha. La columna de la tabla de dimensiones es exactamente la columna que necesita para el conjunto de resultados:
No me gustó la consulta que recibí cuando lo armé todo. Puede haber problemas con el orden de combinación al combinar
OUTER APPLY
yINNER JOIN
. Para obtener el orden de unión que quería, lo reescribí con una subconsulta:No sé cuántos datos tiene, por lo que podría no ser importante para usted. Pero el plan se ve como yo quiero:
Los resultados coinciden con los suyos:
fuente
Aquí no uso la tabla de calendario, sino una tabla de números naturales nums.dbo.nums (espero que también la tenga, si no, puede generarse fácilmente)
Tengo la respuesta ligeramente diferente de la suya ('JOSH' <-> 'JAMES') porque sus datos contienen estas 2 filas:
con la misma cuenta y fecha asignada y no especificó cuál debe tomarse en esta situación.
fuente
De ninguna manera es una solución de aspecto limpio, pero parece proporcionar los resultados que está buscando (estoy seguro de que otros tendrán consultas agradables, limpias y totalmente optimizadas para usted).
fuente
Utilicé la tabla de dimensiones de fecha de Aaron Bertrand, como también mencionas en tu pregunta (que es una tabla muy útil para tales escenarios) y escribí el siguiente código:
Agregué la
EndOfMonth
columna a la#dim
tabla (justo después de laFirstOfMonth
columna) usando el siguiente código:Y la solucion:
fuente
Triangle ¡ÚNETE por la victoria!
Los resultados son:
Plan de ejecución interactivo aquí.
Estadísticas de E / S y TIEMPO (truncado todos los valores cero después de lecturas lógicas):
Consulta para crear las tablas temporales necesarias y prueba la declaración T-SQL que sugiero:
fuente