Retrieve rows from sql table based on specific value

Viewed 78

I have created the following table:

USE [myTestDB]
GO

SET ANSI_NULLS ON
GO

SET QUOTED_IDENTIFIER ON
GO

CREATE TABLE [dbo].[test](
    [id] [numeric](19, 0) NOT NULL,
    [action] [nvarchar](255) NULL,
    [masterid] [numeric](19, 0) NULL
) ON [PRIMARY]
GO

Data on table:

id       action  masterid
1906035  001     514
1906057  002     514
1906064  002     514
1906956  003     514
1907007  002     514
1907010  004     514
1907097  002     514

All rows have the same masterid, and I only want to return rows whose value of action is 002 and they are placed right after action 001, and before any other actions.

Rows that have value 002 after any other action (e.g. 003, 004), must not be returned.

What I want to achieve, is this:

id       action  masterid
1906057  002     514
1906064  002     514

Using the following query, returns all rows with action 002:

select t.[id]
      ,t.[action]
      ,t.[masterid]
from [myTestDB].[dbo].[test] t
left join [myTestDB].[dbo].[test] t2 on (t2.masterid = t.masterid and t2.action = 001)
where t.action = 002
and t.id > t2.id
id       action   masterid
1906057  002      514
1906064  002      514  
1907007  002      514
1907097  002      514

How can I exclude rows with IDs 1907007 & 1907097 that appear after actions 003 & 004?

Thank you in advance!

1 Answers

I would adress this as a gaps-and-islands problem. First, define groups of records that reset everytime action "001" is seen. Then, count the number of non-"002" records from the beginning of each group, and finally filter:

select id, action, masterid
from (
    select t.*, 
        sum(case when action in ('001', '002') then 0 else 1 end) over(partition by masterid, grp order by id) as flag
    from (
        select t.*, 
            sum(case when action = '001' then 1 else 0 end) over(partition by masterid order by id) as grp
        from test t
    ) t
) t
where action = '002' and flag = 0 and grp > 0

Demo on DB Fiddle:

     id | action | masterid
------: | :----- | -------:
1906057 | 002    |      514
1906064 | 002    |      514
Related