You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Oracle Spatial中如何将有序单行线合并为单条连续线?

Oracle Spatial 有序线要素合并为单条连续线的解决方案

问题背景

现有一系列有序的MDSYS.SDO_GEOMETRY类型(类型码4402)线要素,需合并为一条同类型的单条连续线(顶点合并为单一SDO_ORDINATE_ARRAY)。但使用SDO_UTIL.APPEND、SDO_AGGR_LRS_CONCAT会生成多段线(类型码4406),SDO_UTIL.CONCAT_LINES生成单线但顶点存在错误。

可行实现方法

方法一:通过顶点提取+重组实现(纯SQL)

核心思路是提取所有线的顶点,按顺序去重相邻重复顶点,再重新构建单线要素:

WITH line_vertices AS (
    -- 按线的顺序和顶点序号提取所有坐标点
    SELECT 
        line_order, -- 替换为你标识线顺序的字段
        vertex_id,
        x, y
    FROM your_line_table t,
         TABLE(SDO_UTIL.GETVERTICES(t.geom)) v
    ORDER BY line_order, vertex_id
),
unique_vertices AS (
    -- 去重相邻重复的顶点(避免相邻线首尾重复导致冗余点)
    SELECT x, y
    FROM (
        SELECT 
            x, y,
            LAG(x) OVER (ORDER BY line_order, vertex_id) prev_x,
            LAG(y) OVER (ORDER BY line_order, vertex_id) prev_y
        FROM line_vertices
    )
    WHERE prev_x IS NULL OR (x != prev_x OR y != prev_y)
),
ordinate_list AS (
    -- 将坐标聚合为SDO_ORDINATE_ARRAY
    SELECT SDO_ORDINATE_ARRAY(COLLECT(SDO_NUMBER_ARRAY(x, y))) coords
    FROM unique_vertices
)
-- 构建最终的单条线要素
SELECT 
    MDSYS.SDO_GEOMETRY(
        4402, -- 目标类型码
        (SELECT srid FROM your_line_table WHERE line_order = 1), -- 取第一条线的空间参考ID
        NULL,
        MDSYS.SDO_ELEM_INFO_ARRAY(1, 2, 1), -- 单线元素信息:起始位置1,类型2(线),段数1
        (SELECT coords FROM ordinate_list)
    ) AS merged_single_line
FROM dual;

注:如果是3D线,需添加z坐标的处理逻辑,同时调整SDO_ELEM_INFO_ARRAY和坐标聚合逻辑。

方法二:自定义PL/SQL函数

如果SQL方法灵活性不足,可编写自定义函数遍历每条线的顶点,拼接并去重:

CREATE OR REPLACE FUNCTION merge_to_single_line(
    p_ordered_line_ids IN SDO_NUMBER_ARRAY -- 按顺序传入线的ID列表
) RETURN MDSYS.SDO_GEOMETRY IS
    v_merged_ords MDSYS.SDO_ORDINATE_ARRAY;
    v_current_geom MDSYS.SDO_GEOMETRY;
    v_current_ords MDSYS.SDO_ORDINATE_ARRAY;
    v_last_x NUMBER;
    v_last_y NUMBER;
    v_srid NUMBER;
BEGIN
    v_merged_ords := MDSYS.SDO_ORDINATE_ARRAY();
    
    -- 获取空间参考ID(取第一条线的SRID)
    SELECT srid INTO v_srid
    FROM your_line_table
    WHERE line_id = p_ordered_line_ids(1);
    
    FOR i IN 1..p_ordered_line_ids.COUNT LOOP
        -- 获取当前线要素
        SELECT geom INTO v_current_geom
        FROM your_line_table
        WHERE line_id = p_ordered_line_ids(i);
        
        v_current_ords := v_current_geom.SDO_ORDINATES;
        
        IF v_merged_ords.COUNT = 0 THEN
            -- 第一条线:直接添加所有顶点
            FOR j IN 1..v_current_ords.COUNT LOOP
                v_merged_ords.EXTEND;
                v_merged_ords(v_merged_ords.COUNT) := v_current_ords(j);
            END LOOP;
            -- 记录最后一个顶点坐标
            v_last_x := v_current_ords(v_current_ords.COUNT - 1);
            v_last_y := v_current_ords(v_current_ords.COUNT);
        ELSE
            -- 后续线:跳过与前一条线终点重复的起始顶点
            FOR j IN 1..v_current_ords.COUNT LOOP
                IF j = 1 THEN
                    IF v_current_ords(j) = v_last_x AND v_current_ords(j+1) = v_last_y THEN
                        CONTINUE; -- 跳过重复起始点
                    END IF;
                END IF;
                v_merged_ords.EXTEND;
                v_merged_ords(v_merged_ords.COUNT) := v_current_ords(j);
            END LOOP;
            -- 更新最后一个顶点坐标
            v_last_x := v_current_ords(v_current_ords.COUNT - 1);
            v_last_y := v_current_ords(v_current_ords.COUNT);
        END IF;
    END LOOP;
    
    -- 返回合并后的单线要素
    RETURN MDSYS.SDO_GEOMETRY(
        4402,
        v_srid,
        NULL,
        MDSYS.SDO_ELEM_INFO_ARRAY(1, 2, 1),
        v_merged_ords
    );
EXCEPTION
    WHEN NO_DATA_FOUND THEN
        RAISE_APPLICATION_ERROR(-20001, "指定的线ID不存在");
    WHEN OTHERS THEN
        RAISE;
END;
/

调用示例:

SELECT merge_to_single_line(SDO_NUMBER_ARRAY(101,102,103)) AS merged_line
FROM dual;

注:SDO_NUMBER_ARRAY(101,102,103)需替换为你实际的有序线ID列表。

关键注意事项

  1. 必须确保输入的线要素严格连续且顺序正确,否则合并后的线会出现断裂或逻辑错误
  2. 合并后可用SDO_GEOM.VALIDATE_GEOMETRY_WITH_CONTEXT函数验证要素有效性
  3. 处理3D线时,需在代码中增加z坐标的判断与拼接逻辑

内容的提问来源于stack exchange,提问作者gurunara5

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.07 11:46:05