Buen día,
Compruebe si la siguiente solución resuelve todas sus necesidades. Lo probé con sus datos y con algunas filas más, pero siempre es mejor volver a verificar. A primera vista, parece que devuelve el resultado solicitado. Agregaré alguna explicación más adelante
La consulta que estoy usando es esta:
DECLARE @Date DATE = '2018-06-12';
with MyCTE as (
SELECT
t.CustName,t.Country,t.RecordedTime,t.CurrNo, D = CONVERT(DATE, RecordedTime)
,RN_D = ROW_NUMBER()
OVER (partition by t.CustName order by t.CurrNo desc)
,RN = ROW_NUMBER()
OVER (partition by t.CustName order by t.CurrNo)
,RN_Old = ROW_NUMBER()
OVER (partition by t.CustName, (CASE WHEN CONVERT(DATE, RecordedTime) < @Date then 0 else 1 END) order by t.CurrNo desc)
,Cnt = COUNT(*)
OVER (partition by t.CustName)
,CntToday = COUNT(CASE WHEN CONVERT(DATE, RecordedTime) = @Date THEN 1 ELSE NULL END)
OVER (partition by t.CustName)
FROM Test t
where
-- returns rows untill current date
CONVERT (DATE, RecordedTime) <= @Date
-- only if relevnat to current date
and EXISTS (
SELECT * FROM test t0
where CONVERT (DATE, RecordedTime) = @Date and t0.CustName = t.CustName
)
)
,MyCTE2 as (
select
CustName, Country, RecordedTime, D, CurrNo, RN_D, RN, Cnt, t2.c, History, CntToday, RN_Old
from MyCTE t1
left JOIN (select * from (values(1, 'NEW'),(1, 'BEFORE')) t2(c, History) ) t2
on t1.CurrNo = t2.c
and CntToday > 1
and D = @Date
where
RN_D = 1
or (RN = 1 and D = @Date)
or (RN_Old = 1 and D < @Date)
)
,MyCTE3 as (
select CustName, Country, RecordedTime
-- unmarke the bellow comment in order to get the accessories columns I used
-- This is recommended to understand the line-of-thinking
--, D, c, RN_D, RN, CurrNo, Cnt, CntToday, RN_Old
, History = CASE
WHEN CurrNo = 1 and Cnt = 1 then 'NEW'
WHEN RN_D = 1 then 'CURRENT'
else ISNULL(History,'BEFORE')
END
from MyCTE2
)
select CustName, Country, RecordedTime--, D, c, RN_D, RN, CurrNo, Cnt, CntToday, RN_Old
,Audit = CASE when History='New' then 'ADD' else 'CHANGE' END
, History
from MyCTE3
Para simplificar la prueba, inserto la consulta completa en la función de tabla
DROP FUNCTION IF EXISTS dbo.F
GO
CREATE FUNCTION dbo.F(@Date DATE)
RETURNS TABLE AS RETURN (
--DECLARE @Date DATE = '2018-06-12';
with MyCTE as (
SELECT
t.CustName,t.Country,t.RecordedTime,t.CurrNo, D = CONVERT(DATE, RecordedTime)
,RN_D = ROW_NUMBER()
OVER (partition by t.CustName order by t.CurrNo desc)
,RN = ROW_NUMBER()
OVER (partition by t.CustName order by t.CurrNo)
,RN_Old = ROW_NUMBER()
OVER (partition by t.CustName, (CASE WHEN CONVERT(DATE, RecordedTime) < @Date then 0 else 1 END) order by t.CurrNo desc)
,Cnt = COUNT(*)
OVER (partition by t.CustName)
,CntToday = COUNT(CASE WHEN CONVERT(DATE, RecordedTime) = @Date THEN 1 ELSE NULL END)
OVER (partition by t.CustName)
FROM Test t
where
-- returns rows untill current date
CONVERT (DATE, RecordedTime) <= @Date
-- only if relevnat to current date
and EXISTS (
SELECT * FROM test t0
where CONVERT (DATE, RecordedTime) = @Date and t0.CustName = t.CustName
)
)
,MyCTE2 as (
select
CustName, Country, RecordedTime, D, CurrNo, RN_D, RN, Cnt, t2.c, History, CntToday, RN_Old
from MyCTE t1
left JOIN (select * from (values(1, 'NEW'),(1, 'BEFORE')) t2(c, History) ) t2
on t1.CurrNo = t2.c
and CntToday > 1
and D = @Date
where
RN_D = 1
or (RN = 1 and D = @Date)
or (RN_Old = 1 and D < @Date)
)
,MyCTE3 as (
select CustName, Country, RecordedTime
-- unmarke the bellow comment in order to get the accessories columns I used
-- This is recommended to understand the line-of-thinking
--, D, c, RN_D, RN, CurrNo, Cnt, CntToday, RN_Old
, History = CASE
WHEN CurrNo = 1 and Cnt = 1 then 'NEW'
WHEN RN_D = 1 then 'CURRENT'
else ISNULL(History,'BEFORE')
END
from MyCTE2
)
select CustName, Country, RecordedTime--, D, c, RN_D, RN, CurrNo, Cnt, CntToday, RN_Old
,Audit = CASE when History='New' then 'ADD' else 'CHANGE' END
, History
from MyCTE3
--order by CustName, RecordedTime
)
GO
Usando la función es más simple hacer pruebas múltiples, pero probablemente en la producción querrás usar la consulta directa
-- Test
select * from F('2018-06-01') order by CustName , RecordedTime
select * from F('2018-06-02') order by CustName , RecordedTime
select * from F('2018-06-03') order by CustName , RecordedTime
select * from F('2018-06-10') order by CustName , RecordedTime
select * from F('2018-06-11') order by CustName , RecordedTime
select * from F('2018-06-12') order by CustName , RecordedTime
select * from F('2018-06-13') order by CustName , RecordedTime
select * from F('2018-06-14') order by CustName , RecordedTime
/**************** Actualización 2018-08-19 14:05 hora de Israel ****************/
Me doy cuenta de que es importante agregar más información por el bien de la participación en el hilo. Espero que esto sea útil
Primero, comparemos el porcentaje de uso de recursos de acuerdo con los Planes de ejecución de tres consultas:(1) Mi solución, (2) la segunda solución de maulik kansara después de actualizar la primera solución y (3) la primera solución de maulik kansara
Ahora veamos la imagen del EP de maulik kansara second solution:
¡Esta consulta escanea la tabla 11 veces!