All Products
Search
Document Center

PolarDB:ST_Split

Last Updated:Mar 28, 2026

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

ParameterDescription
trajThe trajectory to split.
geomThe spatial geometry object used to split the trajectory. Only Point and MultiPoint are supported.
radius_of_bufferThe radius (in meters) of the buffer built around the Point geometry. See the note below for why a buffer is needed.
configA JSON string specifying the split rule. Only one rule per call.
indexesAn 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.
Split a trajectory based on a geometry object.

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)

Split a trajectory based on a rule.

Available rules

RuleValue typeBehavior
cut_point.max_pointPositive integerSplits every N sampling points. The interval N is the value you specify.
cut_point.even_dividePositive integerDivides the trajectory into N equal parts. If the trajectory has fewer edges than N, each edge becomes a sub-trajectory.
cut_edge.time_intervalPositive time rangeSplits at each edge boundary that crosses the specified time interval. Accepts an optional anchor timestamp: "<interval>, <anchor>".
cut_edge.geohashPositive even numberSplits 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_lengthTime rangeRemoves any edge whose duration exceeds the specified time range.
drop_edge.spatial_distance_2dFloating pointRemoves 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 timestamps

  • ST_leafcount — get the number of sampling points in a trajectory