Reputation: 11336
Given the following data structure:
id | subscription_id | state | created_at | ok
---------+-----------------+-------+----------------------------+----
1 | 1 | error | 2015-06-30 15:20:03.041045 | f
2 | 1 | error | 2015-06-30 15:20:04.582907 | f
3 | 1 | sent | 2015-06-30 22:50:04.50478 | f
4 | 1 | error | 2015-06-30 22:50:06.067279 | f
5 | 1 | error | 2015-07-01 22:50:02.356113 | f
I want to retrieve the last messages with state='error'
until the state
contains something else.
It should return this:
id | subscription_id | state | created_at | ok
---------+-----------------+-------+----------------------------+----
4 | 1 | error | 2015-06-30 22:50:06.067279 | f
5 | 1 | error | 2015-07-01 22:50:02.356113 | f
Following this question and later this one, I ended up with this query below:
SELECT * from (select id, subscription_id, state, created_at,
bool_and(state='error')
OVER (PARTITION BY state order by created_at, id) AS ok
FROM messages ORDER by created_at) m2
WHERE subscription_id = 1;
However, given that I added PARTITION BY state
the query is simply ignoring all state
which does not contain error
and showing this instead:
id | subscription_id | state | created_at | ok
---------+-----------------+-------+----------------------------+----
1 | 1 | error | 2015-06-30 15:20:03.041045 | f
2 | 1 | error | 2015-06-30 15:20:04.582907 | f
4 | 1 | error | 2015-06-30 22:50:06.067279 | f
5 | 1 | error | 2015-07-01 22:50:02.356113 | f
How should the query be made in order to 'stop' after finding a different state and matching following the example described on the top only the ids 4 and 5?
Upvotes: 1
Views: 500
Reputation: 42753
If I correctly understand, you need this:
select * from messages
where
id > (select coalesce(max(id), 0) from messages where state <> 'error')
and
subscription_id = 1
Assuming that id
is unique (PK ?) column and higher id means latest record.
EDIT
Thats correct, as @Marth mentioned, probably you need add ... AND subscription_id = 1
in subquery
Upvotes: 2
Reputation: 24802
No need to PARTITION BY state
, you want to SELECT
rows where all rows afterward (in the created_at ASC
order) are error
, ie bool_and(state = 'error')
is true
:
SELECT * FROM (
SELECT *,
bool_and(state = 'error') OVER (ORDER BY created_at DESC, id) AS only_errors_afterward
FROM sub
) s
WHERE only_errors_afterward
;
┌────┬─────────────────┬───────┬───────────────────────────────┬────┬───────────────────────┐
│ id │ subscription_id │ state │ created_at │ ok │ only_errors_afterward │
├────┼─────────────────┼───────┼───────────────────────────────┼────┼───────────────────────┤
│ 5 │ 1 │ error │ 2015-07-01 22:50:02.356113+02 │ f │ t │
│ 4 │ 1 │ error │ 2015-06-30 22:50:06.067279+02 │ f │ t │
└────┴─────────────────┴───────┴───────────────────────────────┴────┴───────────────────────┘
(2 rows)
Edit: Depending on the expected result you might need a PARTITION BY subscription_id
in the window function.
Upvotes: 2