All Products
Search
Document Center

PolarDB:ST_Split

Last Updated:Mar 28, 2026

Splits a trajectory into an array of sub-trajectories. Three overloaded signatures let you split by a spatial geometry object, a named rule, or explicit point indexes.

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

ParameterTypeDescription
trajtrajectoryThe trajectory to split.
geomgeometryA spatial geometry object used as the split boundary. Only Point and MultiPoint are supported.
radius_of_bufferfloat8Radius of the buffer built around the Point geometry, in meters.
configtextA JSON string specifying one split rule. See Split rules.
indexesint[]Array of sampling point indexes at which to split. Indexes start from 0.

How it works

All three signatures return a trajectory[]. Use unnest() to expand the array into individual rows.

Split by geometry — builds a buffer of radius_of_buffer meters around each Point in geom, then cuts the trajectory at every intersection. With a MultiPoint input, the trajectory may be cut at multiple locations.

Split by rule — applies exactly one named rule from the config JSON string. Only one key is allowed per call.

Split by indexes — cuts the trajectory at each specified index. Providing *n* indexes produces *n-1* sub-trajectories. The start and end points of the trajectory do not need to appear in the index array.

Split a trajectory based on a geometry object.

The diagram below shows how the three rule families differ: cut_point rules split at a sampling point (Point B); cut_edge rules split at a position along an edge (Point C); drop_edge rules delete an edge entirely (the segment between Point A and Point B).

Split a trajectory based on a rule.

Split rules

Specify rules as a JSON string with a single key-value pair, for example: '{"cut_point.max_point":4}'.

RuleValue typeBehavior
cut_point.max_pointPositive integerSplits every *n* sampling points (interval-based).
cut_point.even_dividePositive integerEvenly divides the trajectory into *n* parts. If the trajectory has fewer edges than *n*, each edge becomes a sub-trajectory.
cut_edge.time_intervalPositive time rangeSplits at each time boundary, e.g. "50 minute" or "1 hour, 2000-01-01".
cut_edge.geohashPositive even integerSplits at each Geohash grid boundary at the specified precision. The trajectory must use latitude/longitude data.
drop_edge.temporal_lengthTime rangeRemoves every edge whose temporal length exceeds the threshold.
drop_edge.spatial_distance_2dFloating pointRemoves every edge whose 2D Euclidean distance exceeds the threshold.
Only one rule can be specified per call.

Examples

Split by geometry

Create a trajectory table and insert a sample trajectory with 11 sampling points (SRID 4326), then split it using a MultiPoint with a 23,000-meter 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 query returns 4 sub-trajectories. Each row contains a trajectory JSON with its own leafcount, start_time, end_time, spatial, and timeline fields.

Split by rule

All examples below use a 19-point trajectory defined inline. The cut_point, cut_edge, and drop_edge rules each produce different results.

WITH traj AS (
  SELECT '{"trajectory":{"version":1,"type":"STPOINT","leafcount":19,...}}'::trajectory AS a
)

cut_point.max_point — split every 4 sampling points

SELECT unnest(ST_split(a, '{"cut_point.max_point":4}')) FROM traj;

Returns 5 sub-trajectories: four with 5 points each and a remainder with 3 points.

cut_point.max_point — split every 10 sampling points

SELECT ST_split(a, '{"cut_point.max_point":10}') FROM traj;

Returns 2 sub-trajectories with 10 points each.

cut_point.max_point — split every 3 sampling points

SELECT ST_split(a, '{"cut_point.max_point":3}') FROM traj;

Returns 7 sub-trajectories.

cut_point.even_divide — divide into 100 equal parts

Because the trajectory has only 18 edges and 100 exceeds that count, each edge becomes its own sub-trajectory.

SELECT ST_split(a, '{"cut_point.even_divide":100}') FROM traj;

Returns 18 sub-trajectories, one per edge.

cut_edge.geohash — split at Geohash precision 2

SELECT ST_split(a, '{"cut_edge.geohash":2}') FROM traj;

cut_edge.geohash — split at Geohash precision 20

SELECT ST_split(a, '{"cut_edge.geohash":20}') FROM traj;

drop_edge.spatial_distance_2d — remove edges longer than 13 units

SELECT ST_split(a, '{"drop_edge.spatial_distance_2d":13}') FROM traj;

drop_edge.spatial_distance_2d — remove edges longer than 10 units

SELECT ST_split(a, '{"drop_edge.spatial_distance_2d":10}') FROM traj;

drop_edge.spatial_distance_2d — remove edges longer than 1 unit

When the threshold is smaller than all edge distances, every edge is removed and the result is an empty array.

SELECT ST_split(a, '{"drop_edge.spatial_distance_2d":1}') FROM traj;
-- st_split
-- ----------
--  {}
-- (1 row)

cut_edge.time_interval — split every 50 minutes

SELECT ST_split(a, '{"cut_edge.time_interval":"50 minute"}') FROM traj;

Returns 5 sub-trajectories.

cut_edge.time_interval — split by calendar hour starting at 2000-01-01

SELECT unnest(ST_split(a, '{"cut_edge.time_interval":"1 hour, 2000-01-01"}')) FROM traj;

Returns 4 sub-trajectories, each aligned to a one-hour boundary.

Split by index

Split at indexes 1, 3, and 5 (produces 2 sub-trajectories)

SELECT unnest(ST_split(a, '{1,3,5}'::int[])) FROM traj;

Returns 2 sub-trajectories: index 1 to 3, and index 3 to 5.

Include start and end explicitly

Pass the first (0) and last (ST_leafcount(a) - 1) indexes alongside interior indexes to include the full trajectory span.

SELECT unnest(ST_split(a, '{0}'::int[] || '{0,1,3,5}'::int[] || ST_leafcount(a) - 1)) FROM traj;

Returns 4 sub-trajectories covering the full trajectory from index 0 to the last point.