Search code examples
sqlsql-server

Query to find parent record


I have a table like below

ID  ProductId   Status  Time
---------------------------------------
 1      1       Open    27/01/2025 6:30
 2      1       Closed  27/01/2025 7:30
 3      2       Open    27/01/2025 7:35
 4      3       Open    27/01/2025 7:45
 5      4       Open    27/01/2025 8:45
 6      1       Open    27/01/2025 8:55
 7      2       Closed  28/01/2025 7:30
 8      4       Closed  28/01/2025 8:30
 9      1       Closed  28/01/2025 8:30
10      1       Open    28/01/2025 9:30
11      3       Closed  28/01/2025 9:35
12      4       Open    28/01/2025 9:45

I would like to find the open time and its related closed time of the given product id like below

ProductId   OpenTime            CloseTime
-----------------------------------------------
   1        27/01/2025 6:30     27/01/2025 7:30
   1        27/01/2025 8:55     28/01/2025 8:30
   1        28/01/2025 9:30 
   2        27/01/2025 7:35     28/01/2025 7:30
   3        27/01/2025 7:45     28/01/2025 9:35
   4        27/01/2025 8:45     28/01/2025 8:30
   4        28/01/2025 9:45 

Solution

  • You can also take advantage of the FIRST_VALUE function to find the first value for the product where Status='Closed' following the row where Status='Open' e.g.

    with cte as (
      select ProductId, [Status], StatusTime
        , StatusTime OpenTime
        , first_value(case when [Status] = 'Closed' then StatusTime else null end)
        over (partition by ProductId order by StatusTime asc rows between 1 following and unbounded following) CloseTime
      from dbo.ProductStatus
    )
    select ProductId, OpenTime, CloseTime
    from cte
    where [Status] = 'open'
    order by ProductId, StatusTime asc;
    

    Returns, as requested, for the provided sample data:

    ProductId OpenTime CloseTime
    1 2025-01-27 06:30:00 2025-01-27 07:30:00
    1 2025-01-27 08:55:00 2025-01-28 08:30:00
    1 2025-01-28 09:30:00 NULL
    2 2025-01-27 07:35:00 2025-01-28 07:30:00
    3 2025-01-27 07:45:00 2025-01-28 09:35:00
    4 2025-01-27 08:45:00 2025-01-28 08:30:00
    4 2025-01-28 09:45:00 NULL

    However this could fail if you ever have a mismatched number of open and close events, in which case if you were running SQL Server 2022 you could use the IGNORE NULLS to correct this.