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

基于集合的高效实现:为左列每个值分配右列唯一未使用的最小值

基于集合的高效实现:为左列每个值分配右列唯一未使用的最小值

嗨,我太懂你不想用游标的心情了——逐行处理的游标在数据量上去之后,速度简直慢到让人抓狂。咱们先把需求再理清楚一遍:给每个唯一的Col1值,匹配Col2里最小的、还没被其他Col1占用的选项,最终结果里Col2不能有重复,而且要用上纯集合操作来实现高效运行。

你之前试的select Col1, min(Col2)之所以不行,核心问题是它只盯着单个Col1的最小Col2,完全没考虑这个值是不是已经被其他Col1用掉了,所以才会出现多个Col1都拿到X的错误结果。

下面给你两种高效的纯集合解法,都比游标快得多:

方法一:递归CTE模拟贪心算法

这个思路和你用游标手动分配的逻辑一样,但用集合操作实现,性能提升非常明显:

WITH SortedCol1 AS (
    -- 先给所有唯一的Col1排个顺序,这里按Col1本身的字母/数值序排序
    SELECT DISTINCT Col1,
           ROW_NUMBER() OVER (ORDER BY Col1) AS RowNum
    FROM YourTable
),
RecursiveMatch AS (
    -- 初始步骤:处理第一个Col1,给它分配自己可选的最小Col2
    SELECT sc1.Col1,
           (SELECT TOP 1 t.Col2 FROM YourTable t WHERE t.Col1 = sc1.Col1 ORDER BY t.Col2) AS Col2,
           sc1.RowNum
    FROM SortedCol1 sc1
    WHERE sc1.RowNum = 1

    UNION ALL

    -- 递归步骤:处理下一个Col1,选它可选的、没被前面Col1用过的最小Col2
    SELECT sc1.Col1,
           (SELECT TOP 1 t.Col2 
            FROM YourTable t 
            WHERE t.Col1 = sc1.Col1 
              AND t.Col2 NOT IN (SELECT Col2 FROM RecursiveMatch WHERE RowNum < sc1.RowNum)
            ORDER BY t.Col2) AS Col2,
           sc1.RowNum
    FROM SortedCol1 sc1
    JOIN RecursiveMatch rm ON sc1.RowNum = rm.RowNum + 1
)
-- 最终结果按Col1的顺序输出
SELECT Col1, Col2 FROM RecursiveMatch ORDER BY RowNum;

逻辑解释

  1. SortedCol1:给每个唯一的Col1生成一个连续的序号,确定处理顺序;
  2. 初始递归:先给第一个Col1分配它能选的最小Col2;
  3. 递归迭代:每处理一个Col1,都从它的可选Col2里挑出没被前面的Col1占用的最小值;
  4. 最终输出所有匹配结果。

在你的示例数据里,这个方法会先给A分配X,然后给B分配剩下的最小Y,最后给C分配唯一可选的Z,完全符合预期。

方法二:窗口函数序号匹配法

如果你的数据库支持窗口函数(现在主流数据库都支持),也可以用序号匹配的方式,逻辑更简洁:

WITH RankedCol1 AS (
    -- 给唯一Col1按顺序分配序号
    SELECT DISTINCT Col1,
           ROW_NUMBER() OVER (ORDER BY Col1) AS Col1Rank
    FROM YourTable
),
RankedCol2 AS (
    -- 给唯一Col2按升序分配序号
    SELECT DISTINCT Col2,
           ROW_NUMBER() OVER (ORDER BY Col2) AS Col2Rank
    FROM YourTable
),
Col1Options AS (
    -- 给每个Col1的可选Col2按全局Col2的序号排序,生成该Col1内的选项排名
    SELECT t.Col1,
           t.Col2,
           ROW_NUMBER() OVER (PARTITION BY t.Col1 ORDER BY rc2.Col2Rank) AS OptionRank
    FROM YourTable t
    JOIN RankedCol2 rc2 ON t.Col2 = rc2.Col2
)
-- 匹配Col1的全局序号和它的选项排名,确保每个Col2只被用一次
SELECT rc1.Col1, co.Col2
FROM RankedCol1 rc1
JOIN Col1Options co 
  ON rc1.Col1 = co.Col1 
  AND rc1.Col1Rank = co.OptionRank
ORDER BY rc1.Col1Rank;

逻辑解释

  1. RankedCol1和RankedCol2分别给唯一的Col1和Col2生成全局序号;
  2. Col1Options给每个Col1的可选Col2按全局大小排序,生成该Col1内的选项排名;
  3. 最后通过Col1的全局序号和它的选项排名匹配,保证每个Col2只会被一个Col1选中(因为序号是一一对应的)。

这个方法完全没有递归,纯窗口函数操作,性能非常出色,适合数据量较大的场景。

两种方法都不需要游标,都是纯集合操作,速度能达到游标的上千倍,完美符合你的需求。

内容来源于stack exchange

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.07 09:34:38