sqlsql-serversql-server-2016

Tracking status changes over time


I am trying to track status changes over a given date range. 1/1/2023 - 1/31/2023

Table 1: Customer

filekey activestatus activestatuseffdate
1000 0 1/15/2023

Table 2: StatusHistory

filekey status effdate
1000 0 11/28/2022
1000 1 01/05/2023

The results I'm looking for are:

1/1/2023 1000 0
1/2/2023 1000 0
1/3/2023 1000 0
1/4/2023 1000 0
1/5/2023 1000 1
...
1/14/2023 1000 1
1/15/2023 1000 0
...
1/31/2023 1000 0

This is one of the many, many queries I've tried:

WITH StatusChanges AS (
  SELECT filekey, status, effdate,
         ROW_NUMBER() OVER (PARTITION BY filekey ORDER BY effdate) AS rn
  FROM empactstatushist
  WHERE filekey = 1000 AND effdate <= '2023-01-31'
),
Dates AS (
  SELECT DATEADD(day, n, '2023-01-01') AS DateValue
  FROM (
    SELECT ROW_NUMBER() OVER (ORDER BY a.object_id) - 1 AS n
    FROM sys.objects a
  ) AS n
  WHERE DATEADD(day, n, '2023-01-01') < '2023-02-01'
)
SELECT
  d.DateValue,
  filekey,
  sc.status
FROM Dates d
LEFT JOIN StatusChanges sc ON sc.filekey = 1000
  AND sc.effdate = (
    SELECT MAX(effdate)
    FROM StatusChanges sc2
    WHERE sc2.filekey = 1000 AND sc2.effdate <= d.DateValue
  );

But it doesn't give the results I need. How can I do this?


Solution

  • Try this:

    DECLARE @filekey int = 1000;
    WITH StatusChanges AS (
       
        SELECT filekey, status, activestatuseffdate effdate 
        FROM Customer,
        WHERE filekey = @filekey AND activestatuseffdate < '20230201'
        UNION
        SELECT filekey, status, effdate
        FROM StatusHistory
        WHERE filekey = @filekey AND effdate < '20230201'
    ),
    Dates AS (
      SELECT DATEADD(day, n, '20230101') AS DateValue
      FROM (
        SELECT ROW_NUMBER() OVER (ORDER BY a.object_id) - 1 AS n
        FROM sys.objects a
      ) AS n
      WHERE DATEADD(day, n, '20230101') < '20230201'
    )
    SELECT DateValue, @filekey,
       (
            SELECT TOP 1 status
            FROM StatusChanges
            WHERE Filekey = @filekey AND effdate <= DateValue
            ORDER BY effdate DESC  
       ) effdate 
    FROM Dates
    ORDER BY DateValue
    

    And for all customer files:

    WITH StatusChanges AS (
       
        SELECT filekey, status, activestatuseffdate effdate 
        FROM Customer,
        WHERE activestatuseffdate < '20230201'
        UNION
        SELECT filekey, status, effdate
        FROM StatusHistory
        WHERE effdate < '20230201'
    ),
    Dates AS (
      SELECT DATEADD(day, n, '20230101') AS DateValue
      FROM (
        SELECT ROW_NUMBER() OVER (ORDER BY a.object_id) - 1 AS n
        FROM sys.objects a
      ) AS n
      WHERE DATEADD(day, n, '20230101') < '20230201'
    ),
    DateKeys AS (
         SELECT DateValue, filekey
         FROM Dates
         CROSS JOIN (SELECT DISTINCT filekey FROM Customer) t
    )
    SELECT dk.DateValue, dk.filekey,
       (
            SELECT TOP 1 sc.status
            FROM StatusChanges sc
            WHERE sc.Filekey = dk.filekey AND sc.effdate <= dk.DateValue
            ORDER BY sc.effdate DESC  
       ) effdate 
    FROM DateKeys dk
    

    You'll want to add an ORDER BY to this, but it's not clear whether you want filekey or DateValue first.