| From: | John W Higgins <wishdev(at)gmail(dot)com> |
|---|---|
| To: | "Ray O'Donnell" <ray(at)rodonnell(dot)ie> |
| Cc: | pgsql-general <pgsql-general(at)postgresql(dot)org> |
| Subject: | Re: SQL help: |
| Date: | 2026-08-11 23:51:11 |
| Message-ID: | CAPhAwGy-zYVcZjj8w=iprk6XCEsEehiaAWyLUiMwunHtqXkTFQ@mail.gmail.com |
| Views: | Whole Thread | Raw Message | Download mbox | Resend email |
| Thread: | |
| Lists: | pgsql-general |
Hey Ray,
On Tue, Aug 11, 2026 at 2:33 PM Ray O'Donnell <ray(at)rodonnell(dot)ie> wrote:
> Hi all,
>
> I need some help constructing a query...
>
> aircraft_reg | slot_begin | slot_end |
> booking_id | booking_priority | owner_uid
>
> --------------+------------------------+------------------------+------------+------------------+-----------
> EI-MCG | 2026-08-22 09:00:00+01 | 2026-08-22 10:00:00+01 |
> 361 | 1 | rod
> EI-MCG | 2026-08-22 10:00:00+01 | 2026-08-22 11:00:00+01 |
> 361 | 1 | rod
> EI-MCG | 2026-08-22 11:00:00+01 | 2026-08-22 12:00:00+01 |
> 361 | 1 | rod
> EI-MCG | 2026-08-22 12:00:00+01 | 2026-08-22 13:00:00+01 |
> 217 | 1 | jbloggs
> EI-MCG | 2026-08-22 12:00:00+01 | 2026-08-22 13:00:00+01 |
> 361 | 2 | rod
> EI-MCG | 2026-08-22 13:00:00+01 | 2026-08-22 14:00:00+01 |
> 217 | 1 | jbloggs
> EI-MCG | 2026-08-22 13:00:00+01 | 2026-08-22 14:00:00+01 |
> 361 | 2 | rod
> EI-MCG | 2026-08-22 14:00:00+01 | 2026-08-22 15:00:00+01 |
> 361 | 1 | rod
> EI-MCG | 2026-08-22 15:00:00+01 | 2026-08-22 16:00:00+01 |
> 361 | 1 | rod
> EI-MCG | 2026-08-22 16:00:00+01 | 2026-08-22 17:00:00+01 |
> 361 | 1 | rod
> EI-MCG | 2026-08-22 17:00:00+01 | 2026-08-22 18:00:00+01 |
> 361 | 1 | rod
> EI-MCG | 2026-08-22 18:00:00+01 | 2026-08-22 19:00:00+01 |
> 361 | 1 | rod
>
> So the key function for this work would be lag - it's a window function
which allows you to "look back" x rows (default 1) and see its data.
So lets start with a cte that tags new "groups"
with ordered as (SELECT *, lag(slot_end) over w,
CASE
WHEN slot_begin = lag(slot_end) OVER w
THEN 0
ELSE 1
END AS new_group
FROM slots
WINDOW w AS (
PARTITION BY aircraft_reg, booking_id, booking_priority, owner_uid
ORDER BY slot_begin
)
) select * from ordered
This will return all your rows with an additional column which indicates
whether or not this is a new group. So you use window to create groups of
records based on your 4 unique fields - order by slot_begin - then it walks
the rows and decides if the end time above it matches the start time and if
so it's not a new group. Obviously the first row for any set is a new group
Next up is placing each row in its group
so we start with our ordered cte above
, grouped AS (
SELECT *,
sum(new_group) OVER (
PARTITION BY aircraft_reg, booking_id, booking_priority,
owner_uid
ORDER BY slot_begin
) AS grp
FROM ordered
) select * from grouped
This is sort of a trick but it's simple enough - create a window again
against all our unique fields and then the sum function will sum the
new_group field for any record up until the row in question. So every time
a new group was tagged the sum will go 1 higher for each subsequent row
until the next group is found and then it will increase again and so on and
so forth. Hard for me to explain - but the select * will show it nicely as
the last field.
Finally
SELECT
aircraft_reg,
min(slot_begin) AS slot_begin,
max(slot_end) AS slot_end,
booking_id,
booking_priority,
owner_uid
FROM grouped
GROUP BY
aircraft_reg,
booking_id,
booking_priority,
owner_uid,
grp
ORDER BY slot_begin;
Simply pull your min and max for the begin and end based on your grp column.
Window functions are a very different beast but boy do they help when they
do!
Hope this moves you along.
John W Higgins
>
| From | Date | Subject | |
|---|---|---|---|
| Next Message | Ray O'Donnell | 2026-08-12 11:48:32 | Re: SQL help: |
| Previous Message | Brent Wood | 2026-08-11 22:59:04 | Re: SQL help: |