1

So I have to:

select first 5(or any other number, it will be input) filed2
from table1
where field1=YES
AND
last ID = first ID+5  or something

So normally making:

select first 5 field2 
from table1
where field1=YES 
---------------------------------------
Table1
---------------------------------------
ID  Field1      Field2
1   YES         something1
2   NO          something2      
3   NO          something3
4   YES         something4
5   YES         something5
6   YES         something6  
7   YES         something7
8   YES         something8

would return

something1
something4
something5
something6
something7

but what I need is:

something4
something5
something6
something7
something8

It all has to be in row, so next ID is always +1 to previous one. No field1 "No" in between.

Mark Rotteveel
  • 100,966
  • 191
  • 140
  • 197
  • The row with `id = 4` doesn't actually meet your requirements, because its ID is not +1 the previous ID. – Mark Rotteveel May 14 '21 at 10:41
  • you know how you typicalls find consecutive pairs of the records, right? JOINing table onto itself ? `select t1.id from tablename t1, tablename t2 where t1.id = t2.id+1`. And then you can select top or bottom pair: `select first(1) t1.id from ..... = t2.id+1 order by t1.id asc /* or desc */`. Now you can join the table onto itself 5 times to get 5 consecutive IDs. It would look ugly, but it might be actually good for the SQL engine. Kind of like searching for non-existing matches via `LEFT JOIN t2 ON ... WHERE t2.ID IS NULL` - looks super ugly for human but feels nice for SQL – Arioch 'The May 14 '21 at 20:56
  • `ID is not +1 the previous ID` putting my user support tinfoil hat on, the guy wants "first consecutive (no gap) 5 numbers", but he does not say if those has to be MAX 5 or MIN 5... @MarkRotteveel – Arioch 'The May 14 '21 at 20:59
  • @Arioch'The I guessed that (otherwise I couldn't have posted my answer), but I was just pointing out that the OPs requirements didn't match their expected output. – Mark Rotteveel May 15 '21 at 06:32

1 Answers1

1

I'm going to present a solution that uses a recursive common table expression to select the various 'groups' of contiguous rows. It doesn't exactly meet your requirements, because I think this solution is more generically useful, but it can be modified to achieve your requirement.

This solution requires Firebird 3.0 or later; for simplicity I made field1 a BOOLEAN.

with recursive r as (
  select s.id, s.field1, s.field2, s.prev_id, 
    row_number() over () as group_num
  from s
  where prev_id is null or prev_id < id - 1
  union all
  select s.id, s.field1, s.field2, s.prev_id, r.group_num
  from r
  inner join s
    on s.id = r.id + 1
),
s as (
  select id, field1, field2, 
    lag(id) over (order by id) as prev_id
  from table1
  where field1
),
a as (
  select id, field2, group_num, 
    count(*) over (partition by group_num) as group_count
  from r
)
select id, field2, group_num, group_count
from a
order by id

The CTE r first finds the first row of each group, and then recursively adds the next rows in that group. Be aware: this doesn't work if a group has more than 1024 rows due to recursion limits in Firebird. Each group receives a number, group_num.

The CTE a is used to count the number of rows in each group. The CTE s is used to determine the previous id for each row that matches the condition.

To get the actual result you want, you need to modify the main query to select the first group with 5 or more rows, and fetch the first 5 rows:

-- with clause omitted for brevity, copy it from the previous code block
select field2
from a
where a.group_num = (
  select group_num 
  from a 
  where group_count >= 5 
  order by id 
  fetch first row only
)
order by id
fetch first 5 rows only
Mark Rotteveel
  • 100,966
  • 191
  • 140
  • 197