Split lines into non-overlapping subsets based on points

The ST_Split PostGIS function is probably what you want.

PostGIS 2.2+ now supports Multi* geometries in ST_Split.

For older versions of PostGIS, read on:


To get a single line split by multiple points, you could use something like this multipoint wrapper plpgsql function. I've simplified it just to the "split (multi)lines with (multi)points" case below:

DROP FUNCTION IF EXISTS split_line_multipoint(input_geom geometry, blade geometry);
CREATE FUNCTION split_line_multipoint(input_geom geometry, blade geometry)
  RETURNS geometry AS
$BODY$
    -- this function is a wrapper around the function ST_Split 
    -- to allow splitting multilines with multipoints
    --
    DECLARE
        result geometry;
        simple_blade geometry;
        blade_geometry_type text := GeometryType(blade);
        geom_geometry_type text := GeometryType(input_geom);
    BEGIN
        IF blade_geometry_type NOT ILIKE 'MULTI%' THEN
            RETURN ST_Split(input_geom, blade);
        ELSIF blade_geometry_type NOT ILIKE '%POINT' THEN
            RAISE NOTICE 'Need a Point/MultiPoint blade';
            RETURN NULL;
        END IF;

        IF geom_geometry_type NOT ILIKE '%LINESTRING' THEN
            RAISE NOTICE 'Need a LineString/MultiLineString input_geom';
            RETURN NULL;
        END IF;

        result := input_geom;           
        -- Loop on all the points in the blade
        FOR simple_blade IN SELECT (ST_Dump(ST_CollectionExtract(blade, 1))).geom
        LOOP
            -- keep splitting the previous result
            result := ST_CollectionExtract(ST_Split(result, simple_blade), 2);
        END LOOP;
        RETURN result;
    END;
$BODY$
LANGUAGE plpgsql IMMUTABLE;

-- testing
SELECT ST_AsText(split_line_multipoint(geom, blade))
    FROM (
        SELECT ST_GeomFromText('Multilinestring((-3 0, 3 0),(-1 0, 1 0))') AS geom,
        ST_GeomFromText('MULTIPOINT((-0.5 0),(0.5 0))') AS blade
        --ST_GeomFromText('POINT(-0.5 0)') AS blade
    ) AS T;

Then to create a multipoint geometry to cut by, use ST_Collect and either create it manually from inputs:

SELECT ST_AsText(ST_Collect(
  ST_GeomFromText('POINT(1 2)'),
  ST_GeomFromText('POINT(-2 3)')
));

st_astext
----------
MULTIPOINT(1 2,-2 3)

Or aggregate it from a subquery:

SELECT stusps,
  ST_Multi(ST_Collect(f.the_geom)) as singlegeom
FROM (SELECT stusps, (ST_Dump(the_geom)).geom As the_geom
      FROM somestatetable ) As f
GROUP BY stusps

Upgrade to PostGIS 2.2, where ST_Split was expanded to support splitting by a multiline, a multipoint or (multi)polygon boundary.

postgis=# SELECT postgis_version(),
                  ST_AsText(ST_Split('LINESTRING(0 0, 2 0)', 'MULTIPOINT(0 0, 1 0)'));
-[ RECORD 1 ]---+------------------------------------------------------------
postgis_version | 2.2 USE_GEOS=1 USE_PROJ=1 USE_STATS=1
st_astext       | GEOMETRYCOLLECTION(LINESTRING(1 0,2 0),LINESTRING(0 0,1 0))

I haven't the whole answer for you, but ST_Line_Locate_Point takes a line and a point as arguments, and returns a number between 0 and 1 representing the distance along the line to the position that is closest to the point.

ST_Line_Substring takes a line and two numbers, each between 0 and 1, as arguments. The numbers represent positions on the line as fractional distances. The function returns the line segment that runs between those two positions.

By working with these two functions, you should be able to achieve what you want to do.