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

MySQL合并同结构表并按ID去重:优先保留用户自定义值

实现优先保留用户自定义数据的表合并

这个需求在多表数据合并、优先级覆盖的场景里很常见,我给你分享几个实用的SQL写法,都能精准满足你的需求:

方案一:UNION ALL + 排除已存在的ID(最直观高效)

这个思路特别简单:先取出所有用户自定义的table_saved数据,再补充table_default中那些没有被自定义覆盖的ID数据。这样既保证了自定义数据优先,又自动完成了去重。

-- 先取所有用户保存的自定义数据
SELECT ID, SOME_VAL FROM table_saved
UNION ALL
-- 再取默认表中未被自定义覆盖的部分
SELECT d.ID, d.SOME_VAL
FROM table_default d
WHERE NOT EXISTS (
    SELECT 1 FROM table_saved s 
    WHERE s.ID = d.ID
);

执行这个语句后,你会得到完全符合预期的结果:

IDSOME_VAL
1test
3text
2def_val

这个方案的优势是逻辑清晰,性能也出色——只要给table_saved.ID建了索引,NOT EXISTS的查询效率会非常高。

方案二:使用窗口函数(灵活扩展)

如果以后你可能需要增加更多优先级的表(比如还有一个临时保存数据的table_temp),用窗口函数的写法会更灵活。我们可以给不同表的数据标记优先级,然后取每个ID下优先级最高的记录:

WITH combined_data AS (
    -- 给saved表标记最高优先级(1),default表标记次优先级(2)
    SELECT ID, SOME_VAL, 1 AS priority FROM table_saved
    UNION ALL
    SELECT ID, SOME_VAL, 2 AS priority FROM table_default
)
-- 每个ID只保留优先级最小的那条(也就是saved的数据优先)
SELECT ID, SOME_VAL
FROM combined_data
WHERE (ID, priority) IN (
    SELECT ID, MIN(priority)
    FROM combined_data
    GROUP BY ID
);

或者用ROW_NUMBER()分区的写法,逻辑会更直观:

WITH combined_data AS (
    SELECT 
        ID, 
        SOME_VAL,
        -- 按ID分组,给saved的记录排第1位,default排第2位
        ROW_NUMBER() OVER (
            PARTITION BY ID 
            ORDER BY CASE WHEN source = 'saved' THEN 1 ELSE 2 END
        ) AS rn
    FROM (
        SELECT ID, SOME_VAL, 'saved' AS source FROM table_saved
        UNION ALL
        SELECT ID, SOME_VAL, 'default' AS source FROM table_default
    ) t
)
-- 只取每个ID下排名第1的记录
SELECT ID, SOME_VAL
FROM combined_data
WHERE rn = 1;

这种写法的好处是扩展性极强,以后加新表只需要调整ORDER BY里的优先级规则就行。

方案三:LEFT JOIN + COALESCE(简洁但有局限)

我们也可以用左连接把两个表关联起来,然后用COALESCE函数优先取saved表的值,没有的话就用default表的:

SELECT 
    d.ID,
    -- 如果saved表有对应ID的取值就用它,否则用default的
    COALESCE(s.SOME_VAL, d.SOME_VAL) AS SOME_VAL
FROM table_default d
LEFT JOIN table_saved s ON d.ID = s.ID;

不过这个方案有个小局限:如果table_saved里存在table_default没有的ID(比如用户新增了一个默认表没有的自定义配置),这条数据会被漏掉。如果你的场景不存在这种情况,这个写法是最简洁的;如果存在,那需要再加上UNION ALL补全这部分数据:

SELECT 
    d.ID,
    COALESCE(s.SOME_VAL, d.SOME_VAL) AS SOME_VAL
FROM table_default d
LEFT JOIN table_saved s ON d.ID = s.ID
UNION ALL
-- 补充saved表中存在但default表没有的ID
SELECT ID, SOME_VAL
FROM table_saved s
WHERE NOT EXISTS (
    SELECT 1 FROM table_default d 
    WHERE d.ID = s.ID
);

这样就和方案一的效果完全一致了。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.20 10:21:46