sequence_next_node

Aggregate function that returns the value of the next event after a matched sequential pattern. Implements ClickHouse's sequenceNextNode for flow analysis.

Signature

sequence_next_node(direction VARCHAR, base VARCHAR, timestamp TIMESTAMP,
                   event_column VARCHAR, base_condition BOOLEAN,
                   event1 BOOLEAN [, event2 BOOLEAN, ...]) -> VARCHAR

Parameters:

ParameterTypeDescription
directionVARCHAR'forward' or 'backward'
baseVARCHAR'head', 'tail', 'first_match', or 'last_match'
timestampTIMESTAMPEvent timestamp
event_columnVARCHARValue column (returned as result)
base_conditionBOOLEANCondition for the base/anchor event
event1..eventNBOOLEANSequential event conditions (1 to 32)

Returns: VARCHAR (nullable) -- the value of the adjacent event after a successful sequential match, or NULL if no match or no adjacent event exists.

Direction

Controls which direction to scan for the next event:

DirectionBehavior
'forward'Match events earliest-to-latest, return the event after the last matched step
'backward'Match events latest-to-earliest, return the event before the earliest matched step

Base

Controls which starting point to use when multiple matches exist:

BaseForward behaviorBackward behavior
'head'Start from the first base_condition eventStart from the first base_condition event
'tail'Start from the last base_condition eventStart from the last base_condition event
'first_match'Return the first complete match resultReturn the first complete match result (scanning right-to-left)
'last_match'Return the last complete match resultReturn the last complete match result (scanning right-to-left)

Usage

-- What page do users visit after Home → Product?
SELECT user_id,
  sequence_next_node('forward', 'first_match', event_time, page,
    page = 'Home',        -- base_condition
    page = 'Home',        -- event1
    page = 'Product'      -- event2
  ) as next_page
FROM events
GROUP BY user_id;

-- What page did users come from before reaching Checkout?
SELECT user_id,
  sequence_next_node('backward', 'tail', event_time, page,
    page = 'Checkout',    -- base_condition
    page = 'Checkout'     -- event1
  ) as previous_page
FROM events
GROUP BY user_id;

-- Flow analysis: what happens after the first Home → Product → Cart sequence?
SELECT user_id,
  sequence_next_node('forward', 'first_match', event_time, page,
    page = 'Home',        -- base_condition
    page = 'Home',        -- event1
    page = 'Product',     -- event2
    page = 'Cart'         -- event3
  ) as next_after_cart
FROM events
GROUP BY user_id;

Behavior

Matches ClickHouse's sequenceNextNode exactly (verified against its implementation):

  1. Events are sorted by (timestamp, value) — the value tie-break makes results deterministic when same-timestamp events arrive in arbitrary order.
  2. A single anchor is selected by base:
    • head / tail: the literal first/last event in sorted order, which must itself satisfy base_condition — otherwise the result is NULL.
    • first_match / last_match: the first/last event satisfying both base_condition and event1.
  3. The chain must match consecutive events: eventK must hold at the K-th position from the anchor (ascending for forward, descending for backward). Interleaved non-matching events break the chain, and a failed chain is not retried at other anchors.
  4. On a full match, the value of the event immediately after (forward) or before (backward) the chain is returned; NULL when that position falls off either end. Consequently forward+tail and backward+head always return NULL for one or more steps — the adjacent node would be past the end of the data (ClickHouse behaves identically).
  5. Returns NULL if no anchor exists or the chain does not match.

Differences from ClickHouse

AspectClickHouseduckdb-behavioral
SyntaxsequenceNextNode(direction, base)(ts, val, base_cond, ev1, ...)sequence_next_node(direction, base, ts, val, base_cond, ev1, ...)
Function namecamelCasesnake_case
ParametersTwo-level call syntaxFlat parameter list
Return typeNullable(String)VARCHAR (nullable)
Experimental flagRequires allow_experimental_funnel_functions = 1Always available

Errors

Unknown configuration values abort the query with a descriptive SQL error instead of silently returning NULL:

  • Unknown direction — expected 'forward' or 'backward'
  • Unknown base — expected 'head', 'tail', 'first_match', or 'last_match'

NULL configuration parameters are skipped leniently.

Implementation

OperationComplexity
UpdateO(1) amortized (event append)
CombineO(m) where m = events in other state
FinalizeO(n * k) sequential scan, where n = events, k = event conditions
SpaceO(n) -- all events stored (each includes an Arc<str> value)

Note: Unlike other event-collecting functions where the Event struct is Copy (16 bytes), sequence_next_node uses a dedicated NextNodeEvent struct (32 bytes) that stores an Arc<str> value per event. The Arc<str> enables O(1) clone via reference counting, which significantly reduces combine overhead compared to per-event deep string copying.

See Also