ST_Split splits a trajectory into an array of sub-trajectories. Three signatures are available, each suited to a different split strategy: by geometry, by rule, or by index.
Syntax
trajectory[] ST_Split(trajectory traj, geometry geom, float8 radius_of_buffer);
trajectory[] ST_Split(trajectory traj, text config);
trajectory[] ST_Split(trajectory traj, int[] indexes);Parameters
| Parameter | Description |
|---|---|
traj | The trajectory to split. |
geom | The spatial geometry object used to split the trajectory. Only Point and MultiPoint are supported. |
radius_of_buffer | The radius (in meters) of the buffer built around the Point geometry. See the note below for why a buffer is needed. |
config | A JSON string specifying the split rule. Only one rule per call. |
indexes | An integer array of point indexes at which to split. Indexes start from 0. |
Split by geometry
ST_Split(trajectory traj, geometry geom, float8 radius_of_buffer)
Splits the trajectory at any point that falls within the buffer zone around the geometry. Returns the remaining segments as an array of sub-trajectories. When a MultiPoint geometry is provided, the trajectory may be split at multiple locations.
A trajectory point and a geometry object rarely intersect exactly due to floating-point precision. The radius_of_buffer parameter creates a buffer zone around each Point so nearby trajectory points are reliably captured as split locations. Set this value based on your data's coordinate precision and the acceptable spatial tolerance.
Example: Split a trajectory at three points with a 23 km buffer.
CREATE TABLE tr_split_traj (id integer, traj trajectory);
INSERT INTO tr_split_traj VALUES (
3,
ST_MakeTrajectory(
'STPOINT'::leaftype,
st_geomfromtext('LINESTRING(99.027 29.7555,99.313 29.9975,99.852 30.0745,104.879 35.0795,105.044 35.1235,105.187 35.0685,109.906 35.0795,110.071 35.1675,110.192 35.0355,110.544 35.0245,111.017 34.8045)', 4326),
ARRAY[
'2010-01-01 14:30'::timestamp, '2010-01-01 15:00', '2010-01-01 15:10',
'2010-01-01 15:20', '2010-01-01 15:30', '2010-01-01 15:40',
'2010-01-01 15:50', '2010-01-01 16:00', '2010-01-01 16:10',
'2010-01-01 16:20', '2010-01-01 16:30'
],
'{"leafcount":11,"attributes":{"velocity":{"type":"integer","length":2,"nullable":true,"value":[120,130,140,150,160,170,180,190,200,210,220]}}}'
)
);
SELECT id, unnest(ST_Split(traj, st_geomfromtext('MULTIPOINT(100 30,105 35,110 35)'), 23000)) AS subtraj
FROM tr_split_traj;The MULTIPOINT geometry splits the trajectory into 4 sub-trajectories, one for each segment between the three split points.
Split by rule
ST_Split(trajectory traj, text config)
Splits the trajectory based on a JSON rule. Pass exactly one rule per call.
The config rules fall into three categories, illustrated below:
cut_point.*— splits at a sampling point (Point B in the diagram)cut_edge.*— splits at an edge between two sampling points (Point C in the diagram)drop_edge.*— removes an edge between two sampling points (the edge between Point A and Point B)

Available rules
| Rule | Value type | Behavior |
|---|---|---|
cut_point.max_point | Positive integer | Splits every N sampling points. The interval N is the value you specify. |
cut_point.even_divide | Positive integer | Divides the trajectory into N equal parts. If the trajectory has fewer edges than N, each edge becomes a sub-trajectory. |
cut_edge.time_interval | Positive time range | Splits at each edge boundary that crosses the specified time interval. Accepts an optional anchor timestamp: "<interval>, <anchor>". |
cut_edge.geohash | Positive even number | Splits so that each sub-trajectory falls within a single Geohash grid cell at the given precision. The trajectory data must use latitude and longitude coordinates. |
drop_edge.temporal_length | Time range | Removes any edge whose duration exceeds the specified time range. |
drop_edge.spatial_distance_2d | Floating point | Removes any edge whose 2D Euclidean distance exceeds the specified value. |
Examples
`cut_point.max_point` — split every 4 points
WITH traj AS (
SELECT '{"trajectory":{"version":1,"type":"STPOINT","leafcount":19,...}}'::trajectory AS a
)
SELECT unnest(ST_Split(a, '{"cut_point.max_point":4}')) FROM traj;
-- Returns 5 sub-trajectories: four with 5 points each, one remainder with 3 points.`cut_point.even_divide` — divide into equal parts
When the requested number of parts exceeds the number of edges, each edge becomes its own sub-trajectory.
-- Request 100 parts from a 19-point trajectory (18 edges -> 18 sub-trajectories)
SELECT ST_Split(a, '{"cut_point.even_divide":100}') FROM traj;`cut_edge.time_interval` — split on a fixed time interval
Pass "<interval>" to split based on elapsed time, or "<interval>, <anchor_date>" to align splits to fixed clock boundaries.
-- Split every 50 minutes from the trajectory's start time
SELECT ST_Split(a, '{"cut_edge.time_interval":"50 minute"}') FROM traj;
-- Split at fixed 1-hour boundaries anchored to 2000-01-01 00:00
SELECT unnest(ST_Split(a, '{"cut_edge.time_interval":"1 hour, 2000-01-01"}')) FROM traj;`cut_edge.geohash` — split by Geohash grid
The value specifies the Geohash precision (must be a positive even number). Higher values produce finer grids and more splits.
-- Precision 2: coarse grid, fewer sub-trajectories
SELECT ST_Split(a, '{"cut_edge.geohash":2}') FROM traj;
-- Precision 20: fine grid, more sub-trajectories
SELECT ST_Split(a, '{"cut_edge.geohash":20}') FROM traj;cut_edge.geohash requires the trajectory to use latitude and longitude coordinates.`drop_edge.spatial_distance_2d` — remove edges by 2D distance
Removes any edge whose 2D Euclidean distance exceeds the specified value. If all edges are removed, the function returns an empty array ({}).
-- Remove edges longer than 13 units -> returns 1 sub-trajectory (18 remaining points)
SELECT ST_Split(a, '{"drop_edge.spatial_distance_2d":13}') FROM traj;
-- Remove edges longer than 10 units -> returns 7 sub-trajectories
SELECT ST_Split(a, '{"drop_edge.spatial_distance_2d":10}') FROM traj;
-- Remove edges longer than 1 unit -> all edges removed, returns {}
SELECT ST_Split(a, '{"drop_edge.spatial_distance_2d":1}') FROM traj;Split by index
ST_Split(trajectory traj, int[] indexes)
Splits the trajectory at the specified point indexes. Indexes start from 0. Given n indexes, the function produces n-1 sub-trajectories. The start and end points of the trajectory do not need to be included in the index array.
Example: Split at indexes 1, 3, and 5 — returns 2 sub-trajectories (segments [1–3] and [3–5]).
WITH traj AS (
SELECT '{"trajectory":{"version":1,"type":"STPOINT","leafcount":19,...}}'::trajectory AS a
)
SELECT unnest(ST_Split(a, '{1,3,5}'::int[])) FROM traj;
-- Returns 2 sub-trajectories.Example: Including the start (0) and end (ST_leafcount(a) - 1) indexes in the array has no effect on split behavior, but makes the index boundaries explicit.
SELECT unnest(ST_Split(a, '{0}'::int[] || '{0,1,3,5}'::int[] || ST_leafcount(a) - 1)) FROM traj;
-- Returns 4 sub-trajectories (duplicate index 0 is ignored).What's next
ST_MakeTrajectory— construct a trajectory from geometry and timestampsST_leafcount— get the number of sampling points in a trajectory