sql - 链式 CTE 未按顺序执行?PostgreSQL
问题描述
我有以下功能:
CREATE OR REPLACE FUNCTION fn_cleanup_proxies(cleanup_range integer, proxies json)
RETURNS udt_cleanup_count AS $func$
DECLARE result_count udt_cleanup_count;
BEGIN
WITH input_proxies AS (SELECT * FROM json_populate_recordset(null::udt_proxy, proxies)),
old_proxies AS (SELECT p.id, p.address, p.isp_id FROM proxy AS p INNER JOIN input_proxies AS i ON p.address = i.address AND p.port = i.port AND p.type_id = i.type_id),
old_proxies_city AS (SELECT address FROM old_proxies WHERE address NOT IN (SELECT address FROM proxy WHERE modified_date > NOW() - INTERVAL '1 days' * cleanup_range)),
old_proxies_isp AS (SELECT isp_id FROM old_proxies WHERE isp_id NOT IN (SELECT isp_id FROM proxy WHERE modified_date > NOW() - INTERVAL '1 days' * cleanup_range)),
deleted_proxy AS (DELETE FROM proxy WHERE id IN (SELECT id FROM old_proxies) RETURNING *),
deleted_isp AS (DELETE FROM isp WHERE id IN (SELECT * FROM old_proxies_isp) RETURNING *),
deleted_city AS (DELETE FROM city WHERE proxy_address IN (SELECT * FROM old_proxies_city) RETURNING *)
SELECT (SELECT count(*) FROM deleted_proxy), (SELECT count(*) FROM deleted_city), (SELECT count(*) FROM deleted_isp)
INTO result_count.proxy_count, result_count.city_count, result_count.isp_count;
RETURN result_count;
END
$func$ LANGUAGE plpgsql;
当我执行它时,我收到以下错误:
ERROR: update or delete on table "isp" violates foreign key constraint "proxy_isp_id_fkey" on table "proxy"
DETAIL: Key (id)=(23969) is still referenced from table "proxy".
我得到的印象是链接的 CTE 不是按顺序执行,而是并行执行。这是因为当我手动依次执行以下三个删除语句时:
deleted_proxy AS (DELETE FROM proxy WHERE id IN (SELECT id FROM old_proxies) RETURNING *),
deleted_isp AS (DELETE FROM isp WHERE id IN (SELECT * FROM old_proxies_isp) RETURNING *),
deleted_city AS (DELETE FROM city WHERE proxy_address IN (SELECT * FROM old_proxies_city) RETURNING *)
我没有遇到任何约束问题,一切似乎都很好。
另外,正如您可能从我的查询中注意到的那样,我对 PostgreSQL 有点陌生,所以如果有任何改进我的查询的建议,请随时发表评论。
解决方案
我的印象是链接的 CTE 不是按顺序执行,而是并行执行
你说的对。从手册中引用
WITH 中的子语句彼此同时执行,并与主查询同时执行。因此,当在 WITH 中使用数据修改语句时,指定更新实际发生的顺序是不可预测的
由于您实际上并未将RETURNING *
子句的结果用于 DELETE,为什么还要使用 CTE?只需一个接一个地运行所有语句。
推荐阅读
- oracle12c - Oracle 12c 无法启动 oracle 服务(错误 2)
- javascript - 更改时更新 PHP 会话变量
- javascript - 验证日期输入 - 时间戳微服务
- mysql - 这有什么问题?
- dialogflow-es - Dialogflow 中的 Google 助理测验操作
- python - 如何在条件下用另一个 col 值替换一个 col 值
- reactjs - 有没有更好的方法将数据从子组件传递到父组件中的函数而不使用 bind()?
- docker - 如何在配置自定义映像时将文件夹从 docker 复制到主机
- python - 用空格替换 \n
- cryptography - 将密码转换为 256 位密钥