December 22, 2016 at 9:37 am
Thom A (12/22/2016)
Fully Windowed, and VALID included.
WITH CTE (EVENT_ID, EVENT_RANK, MIN_AGE, MAX_AGE, C_MIN, C_MAX) AS
(
SELECT A.EVENT_ID,
A.EVENT_RANK,
A.MIN_AGE,
A.MAX_AGE,
CASE WHEN ISNULL(A.MIN_AGE,0) < MAX(A.MIN_AGE) OVER (PARTITION BY A.EVENT_ID ORDER BY A.EVENT_RANK
ROWS BETWEEN UNBOUNDED PRECEDING
AND CURRENT ROW)
THEN MAX(A.MIN_AGE) OVER (PARTITION BY A.EVENT_ID ORDER BY A.EVENT_RANK
ROWS BETWEEN UNBOUNDED PRECEDING
AND CURRENT ROW)
ELSE A.MIN_AGE END AS C_MIN,
CASE WHEN ISNULL(A.MAX_AGE,0) < MAX(A.MAX_AGE) OVER (PARTITION BY A.EVENT_ID ORDER BY A.EVENT_RANK
ROWS BETWEEN UNBOUNDED PRECEDING
AND CURRENT ROW)
AND ISNULL(A.MAX_AGE,0) <= ISNULL(LAG(A.MAX_AGE) OVER (PARTITION BY A.EVENT_ID ORDER BY A.EVENT_RANK), A.MAX_AGE)
THEN MAX(A.MAX_AGE) OVER (PARTITION BY A.EVENT_ID ORDER BY A.EVENT_RANK
ROWS BETWEEN UNBOUNDED PRECEDING
AND CURRENT ROW)
ELSE A.MAX_AGE END AS C_MAX
FROM ATABLE A)
SELECT *,
CASE WHEN C.MAX_AGE < C.C_MIN THEN 0
WHEN C.MIN_AGE > C.C_MAX THEN 0
ELSE 1 END AS VALID
FROM CTE C
ORDER BY C.EVENT_ID,
C.EVENT_RANK;
If this really does work, the "MARK AS SOLUTION" button is always appreciated 😉
I think this can be greatly simplified, but the logic is not really clear and the sample is too small to cover all of the cases. Specifically it would help to have more than one record after the invalid record and it would help to have more than one invalid record. Even as it stands, the current query can be simplified. Specifically
-- This formula is unnecessarily complex
CASE WHEN ISNULL(A.MIN_AGE,0) < MAX(A.MIN_AGE) OVER (PARTITION BY A.EVENT_ID ORDER BY A.EVENT_RANK
ROWS BETWEEN UNBOUNDED PRECEDING
AND CURRENT ROW)
THEN MAX(A.MIN_AGE) OVER (PARTITION BY A.EVENT_ID ORDER BY A.EVENT_RANK
ROWS BETWEEN UNBOUNDED PRECEDING
AND CURRENT ROW)
ELSE A.MIN_AGE END AS C_MIN,
-- It is equivalent to
MAX(A.MIN_AGE) OVER (PARTITION BY A.EVENT_ID ORDER BY A.EVENT_RANK
ROWS BETWEEN UNBOUNDED PRECEDING
AND CURRENT ROW)
AS C_MIN,
1) A.MIN_AGE is the current row, so it is included in ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW.
2) By the definition of MAX() and the fact that A.MIN_AGE is included in the set, we know that A.MIN_AGE <= MAX(A.MIN_AGE) OVER(...).
3) If A.MIN_AGE is NULL or A.MIN_AGE < MAX(A.MIN_AGE) OVER(...), then we are outputting MAX(A.MIN_AGE) OVER(...)
4) If the first case fails, then we know that A.MIN_AGE >= MAX(A.MIN_AGE) OVER(...), but we've already shown that A.MIN_AGE <= MAX(A.MIN_AGE) OVER(...), so we know that A.MIN_AGE = MAX(A.MIN_AGE) OVER(...), so we can substitute equal expressions and output MAX(A.MIN_AGE) OVER(...).
So, in all cases, we are outputting MAX(A.MIN_AGE) OVER(...).
Drew
J. Drew Allen
Business Intelligence Analyst
Philadelphia, PA
December 22, 2016 at 9:38 am
Sorry Thom,
I have tested with a different dataset and it isnt returning correctly.
INSERT [dbo].[ATABLE] ([EVENT_ID], [EVENT_RANK], [MIN_AGE], [MAX_AGE]) VALUES (1205, 1, NULL, 55.00000000089)
GO
INSERT [dbo].[ATABLE] ([EVENT_ID], [EVENT_RANK], [MIN_AGE], [MAX_AGE]) VALUES (1205, 2, 23, NULL)
GO
INSERT [dbo].[ATABLE] ([EVENT_ID], [EVENT_RANK], [MIN_AGE], [MAX_AGE]) VALUES (1205, 3, 25, 36)
GO
This returns c min 25 which is correct and c_max as 55 which is wrong, it should be 36.
Sorry to be such a pain, it is such an elegant solution I am sure it is just a tweak.
Thanks
Oliver
Viewing 3 posts - 16 through 17 (of 17 total)
You must be logged in to reply to this topic. Login to reply