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

  1. Events are sorted by timestamp.
  2. The function scans in the specified direction to find a sequential chain of events matching event1, event2, ..., eventN.
  3. The starting event must satisfy base_condition.
  4. For forward: returns the value of the event immediately after the last matched step.
  5. For backward: event1 matches at the starting position (later timestamp), then event2 matches at an earlier position, etc. Returns the value of the event immediately before the earliest matched step.
  6. Returns NULL if no complete match is found, or if no adjacent event exists.

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

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