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

如何复用同一SELECT查询结果删除多表中符合条件的数据?

问题描述

我的表结构及数据示例如下:

name | version | processed | processing | updated  | ref_time 
------+---------+-----------+------------+----------+----------
 abc  |       1 | t         | f          | 27794395 | 27794160
 def  |       1 | t         | f          | 27794395 | 27793440
 ghi  |       1 | t         | f          | 27794395 | 27793440
 jkl  |       1 | f         | f          | 27794395 | 27794160
 mno  |       1 | t         | f          | 27794395 | 27793440
 pqr  |       1 | f         | t          | 27794395 | 27794160

我编写了生成待删除ref_time列表的查询:

WITH main AS
(
    SELECT ref_time,
        ROUND(AVG(processed::int) * 100, 1) percent
    FROM status_table
    GROUP BY ref_time ORDER BY ref_time DESC, percent DESC
)
SELECT ref_time FROM main WHERE percent=100 OFFSET 2;

该查询返回结果示例:

ref_time 
----------
 27794880
 27794160

并通过以下语句删除了status_table中符合条件的数据:

DELETE FROM status_table
WHERE ref_time IN 
(
    WITH main AS
    (
        SELECT ref_time,
            ROUND(AVG(processed::int) * 100, 1) percent
        FROM status_table
        GROUP BY ref_time ORDER BY ref_time DESC, percent DESC
    )
    SELECT ref_time FROM main WHERE percent=100 OFFSET 2
);

现在需要基于同一组ref_time值删除data_table中的对应数据,如何避免重复编写生成ref_time列表的查询?

解决方案

方法1:共享CTE一次性删除多表数据(PostgreSQL适用)

将生成目标ref_time的逻辑放在外层CTE中,后续两次删除操作直接复用该CTE的结果:

WITH target_ref_times AS (
    SELECT ref_time
    FROM (
        SELECT ref_time,
               ROUND(AVG(processed::int) * 100, 1) AS percent,
               ROW_NUMBER() OVER (ORDER BY ref_time DESC, percent DESC) AS rn
        FROM status_table
        GROUP BY ref_time
    ) sub
    WHERE percent = 100 AND rn > 2
)
-- 删除status_table数据
DELETE FROM status_table st
USING target_ref_times trt
WHERE st.ref_time = trt.ref_time;

-- 删除data_table数据
DELETE FROM data_table dt
USING target_ref_times trt
WHERE dt.ref_time = trt.ref_time;

注:这里用ROW_NUMBER()替代原查询的OFFSET 2,逻辑完全等价,且在CTE中更易维护。

方法2:用临时表存储目标ref_time

如果需要多次复用这组ref_time,或者数据库不支持跨删除语句共享CTE,可以先将结果存入临时表:

-- 创建临时表存储待删除的ref_time
CREATE TEMP TABLE temp_ref_times AS
WITH main AS
(
    SELECT ref_time,
        ROUND(AVG(processed::int) * 100, 1) percent
    FROM status_table
    GROUP BY ref_time ORDER BY ref_time DESC, percent DESC
)
SELECT ref_time FROM main WHERE percent=100 OFFSET 2;

-- 删除status_table数据
DELETE FROM status_table
WHERE ref_time IN (SELECT ref_time FROM temp_ref_times);

-- 删除data_table数据
DELETE FROM data_table
WHERE ref_time IN (SELECT ref_time FROM temp_ref_times);

-- 临时表会在会话结束后自动清理,也可手动删除
DROP TABLE temp_ref_times;

方法3:封装成自定义函数复用逻辑

如果该ref_time筛选逻辑会频繁使用,可封装成函数:

CREATE OR REPLACE FUNCTION get_old_ref_times()
RETURNS TABLE(ref_time INT) AS $$
BEGIN
    RETURN QUERY
    WITH main AS
    (
        SELECT ref_time,
            ROUND(AVG(processed::int) * 100, 1) percent
        FROM status_table
        GROUP BY ref_time ORDER BY ref_time DESC, percent DESC
    )
    SELECT ref_time FROM main WHERE percent=100 OFFSET 2;
END;
$$ LANGUAGE plpgsql;

-- 删除数据时直接调用函数
DELETE FROM status_table WHERE ref_time IN (SELECT * FROM get_old_ref_times());
DELETE FROM data_table WHERE ref_time IN (SELECT * FROM get_old_ref_times());

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.13 16:56:01