SQL Range JOIN

A specific, extremely common shape of non-equi join — matching a value against a MIN/MAX pair to find which bucket it falls into.

What & Why

A range join matches a point to the interval containing it. Queryflo attaches each growth.events.created_at value to the matching growth.sessions window for the same user, using an inclusive start and an exclusive end.

See How It Works

BUSINESS QUESTION

Growth attaches each event to the session window for the same user.

iduser_idstarted_atended_atpage_viewsdevice
50011012024-01-16 14:20:00+002024-01-16 14:52:00+008desktop
50021022024-02-10 11:10:00+002024-02-10 11:18:00+003mobile
50031032024-03-13 08:10:00+002024-03-13 09:04:00+0012desktop
50041042024-04-03 12:00:00+00NULL1tablet
50051052024-04-04 09:00:00+002024-04-04 09:21:00+007mobile
50061062024-04-05 10:15:00+002024-04-05 10:42:00+005tablet
50071072024-04-06 13:05:00+002024-04-06 13:38:00+0010desktop
iduser_idevent_namecreated_atproperties
1001101signup2024-01-15 09:12:00+00{"source":"organic"}
1002101activated2024-01-16 14:25:00+00{"step":"workspace"}
1003102signup2024-02-10 11:08:00+00{"source":"paid"}
1004103report_viewed2024-03-12 16:40:00+00{"report":"retention"}
EXAMPLE QUERY
SELECT
  s.id AS session_id,
  e.id AS event_id,
  e.event_name,
  e.created_at AS event_at
FROM growth.sessions s
JOIN growth.events e
  ON e.user_id = s.user_id
 AND e.created_at >= s.started_at
 AND e.created_at < COALESCE(s.ended_at, s.started_at + INTERVAL '4 hours')
ORDER BY session_id, event_at;
RESULT — exact output from the displayed Queryflo rows
session_idevent_idevent_nameevent_at
50011002activated2024-01-16 14:25:00+00

Only event 1002 occurs inside a displayed session window for the same user.

Now You Try

Practice this concept

Growth wants the first 100 events attached to the session window containing each event timestamp.

Available schema
growth

Prefix tables with growth.table_name.

session_idevent_idevent_nameevent_at
growth.events
ColumnType
idbigint
user_idinteger
event_nametext
created_attimestamp with time zone
propertiesjsonb
deprecated_metrictext
growth.sessions
ColumnType
idbigint
user_idinteger
started_attimestamp with time zone
ended_attimestamp with time zone
page_viewsinteger
devicetext
internal_session_scoreinteger
query.sql
Intermediate business practice

Sign up free to try it on a real business scenario