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

求SQL实现按输入范围拆分数值区间并匹配请求容量的查询语句

Solution

搞定这个拆分需求的核心是理清优先级:先从指定的数值范围里提取容量,若还没满足请求的Volume=3,再从原数据的其他区间补充,最后把被取用的部分标记为Yes,剩余部分标记为No。以下是实现这个逻辑的SQL查询(基于PostgreSQL语法,其他数据库可稍作调整):

WITH request_params AS (
    -- 把请求参数定义成CTE,方便后续复用:总需求容量和指定的数值范围
    SELECT 3 AS required_volume,
           unnest(ARRAY[ROW(301, 301), ROW(103, 103)]) AS range(start_num, end_num)
),
record_intersections AS (
    -- 第一步:找出原表记录和请求范围的交集,计算每个交集能提供的容量
    SELECT 
        t.SlNo,
        t.NumberStart AS original_start,
        t.NumberEnd AS original_end,
        t.Volume AS original_volume,
        GREATEST(t.NumberStart, r.start_num) AS intersect_start,
        LEAST(t.NumberEnd, r.end_num) AS intersect_end,
        -- 每个交集对应的容量(假设每个数值对应1单位容量)
        LEAST(t.NumberEnd, r.end_num) - GREATEST(t.NumberStart, r.start_num) + 1 AS intersect_volume,
        rp.required_volume
    FROM table1 t
    CROSS JOIN request_params rp
    CROSS JOIN unnest(rp.range) r
    -- 只保留确实有交集的记录
    WHERE GREATEST(t.NumberStart, r.start_num) <= LEAST(t.NumberEnd, r.end_num)
),
allocated_volumes AS (
    -- 第二步:计算每个原记录需要分配的总容量,优先满足请求范围的需求
    SELECT 
        SlNo,
        original_start,
        original_end,
        original_volume,
        SUM(intersect_volume) AS requested_intersect_volume,
        required_volume,
        -- 取交集总容量、剩余需求、原记录容量三者的最小值,确定实际分配量
        LEAST(SUM(intersect_volume), required_volume, original_volume) AS allocated_total
    FROM record_intersections
    GROUP BY SlNo, original_start, original_end, original_volume, required_volume
    UNION ALL
    -- 处理请求范围没覆盖到,但需要补充容量的记录(如果需求还没满足)
    SELECT 
        t.SlNo,
        t.NumberStart AS original_start,
        t.NumberEnd AS original_end,
        t.Volume AS original_volume,
        0 AS requested_intersect_volume,
        -- 计算还缺多少容量
        rp.required_volume - COALESCE((SELECT SUM(allocated_total) FROM allocated_volumes), 0) AS remaining_required,
        LEAST(t.Volume, rp.required_volume - COALESCE((SELECT SUM(allocated_total) FROM allocated_volumes), 0)) AS allocated_total
    FROM table1 t
    CROSS JOIN request_params rp
    WHERE (SELECT SUM(allocated_total) FROM allocated_volumes) < rp.required_volume
    AND NOT EXISTS (SELECT 1 FROM record_intersections ri WHERE ri.SlNo = t.SlNo)
),
split_segments AS (
    -- 第三步:生成所有拆分后的片段
    -- 1. 请求范围覆盖的拆分片段
    SELECT 
        ri.intersect_start AS NumberStart,
        ri.intersect_end AS NumberEnd,
        'Yes' AS isSplitted,
        -- 确保分配的容量不超过该交集的可用量和剩余需求
        LEAST(ri.intersect_volume, av.allocated_total - COALESCE(SUM(ri2.intersect_volume) OVER (PARTITION BY ri.SlNo ORDER BY ri.intersect_start ROWS BETWEEN UNBOUNDED PRECEDING AND 1 PRECEDING), 0)) AS Volume
    FROM record_intersections ri
    JOIN allocated_volumes av ON ri.SlNo = av.SlNo
    WHERE av.allocated_total > 0
    UNION ALL
    -- 2. 补充容量的拆分片段(从非请求范围取的部分)
    SELECT 
        av.original_start AS NumberStart,
        av.original_start + av.allocated_total - 1 AS NumberEnd,
        'Yes' AS isSplitted,
        av.allocated_total AS Volume
    FROM allocated_volumes av
    WHERE av.requested_intersect_volume = 0 AND av.allocated_total > 0
    UNION ALL
    -- 3. 原记录剩余的未拆分片段
    SELECT 
        -- 计算剩余片段的起始位置
        CASE 
            WHEN EXISTS (SELECT 1 FROM record_intersections ri WHERE ri.SlNo = av.SlNo) THEN 
                GREATEST(av.original_start, (SELECT MAX(ri.intersect_end) FROM record_intersections ri WHERE ri.SlNo = av.SlNo) + 1)
            ELSE av.original_start + av.allocated_total
        END AS NumberStart,
        av.original_end AS NumberEnd,
        'No' AS isSplitted,
        av.original_volume - av.allocated_total AS Volume
    FROM allocated_volumes av
    WHERE av.original_volume - av.allocated_total > 0
)
-- 最终结果按NumberStart排序,和示例输出一致
SELECT NumberStart, NumberEnd, isSplitted, Volume
FROM split_segments
ORDER BY NumberStart;

关键逻辑说明

  • request_params:把请求的总容量和指定范围封装成可复用的CTE,后续修改参数只需要改这里。
  • record_intersections:精准定位原表和请求范围的重叠部分,计算每个重叠区间能提供的容量。
  • allocated_volumes:确定每个原记录需要贡献多少容量,优先用请求范围里的,不够再从其他地方补。
  • split_segments:把原记录拆成三种类型的片段:被请求用掉的(Yes)、补充用掉的(Yes)、剩下的(No)。

如果用的是MySQL、SQL Server这类数据库,需要调整unnest、窗口函数的语法(比如MySQL用JSON_TABLE处理数组,SQL Server用表值构造函数定义请求范围),核心逻辑是通用的。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.06 10:17:41