PostgreSQL存储过程中MySQL FOUND_ROW()的等效替代方案咨询
PostgreSQL 替代 MySQL FOUND_ROWS() 的最佳实现方案
首先明确 MySQL 中 FOUND_ROWS() 的两种典型使用场景,对应 PG 有不同的最优实现:
场景1:获取上一条查询实际返回的行数
直接使用 PG 内置的 GET DIAGNOSTICS 语法即可,这是最贴合原生逻辑的实现,无额外性能损耗。
示例用法:
DECLARE v_row_count INTEGER; BEGIN -- 执行你的查询逻辑 EXECUTE 'SELECT * FROM your_table WHERE id > 10'; -- 获取上一条查询返回的行数,效果和普通场景下的FOUND_ROWS()完全一致 GET DIAGNOSTICS v_row_count = ROW_COUNT; END;
场景2:获取带LIMIT查询的无限制总匹配行数(对应MySQL SQL_CALC_FOUND_ROWS + FOUND_ROWS() 分页场景)
最佳方案是使用窗口函数 count(*) OVER(),不需要额外执行一次count查询,性能更优:
示例用法:
DECLARE v_total_rows INTEGER; BEGIN -- 分页查询同时返回总匹配数 EXECUTE 'SELECT *, count(*) OVER() AS total_rows FROM your_table WHERE id > 10 LIMIT 10 OFFSET 0' INTO STRICT your_record_variable; -- 取第一条结果的total_rows字段即可拿到无LIMIT的总匹配数 v_total_rows := your_record_variable.total_rows; END;
你提供的存储过程迁移注意事项
你给出的原MySQL存储过程还有多处MySQL专属语法需要适配PG,核心修改点如下:
- 移除所有
@前缀的用户变量,替换为DECLARE声明的局部变量,赋值使用:=运算符 - 字符串函数替换:
INSTR()替换为 PG 原生strpos()SPLIT_STR()替换为 PG 原生split_part(字符串, 分隔符, 序号)
- 动态SQL执行逻辑简化:直接使用
EXECUTE 动态SQL字符串即可,不需要PREPARE/DEALLOCATE语句 - 特殊字符转义逻辑适配PG规则,原有防注入替换逻辑可保留,但更推荐使用
format()函数拼接动态SQL,配合%L、%I占位符自动处理转义,安全性更高
迁移后的简化示例:
CREATE OR REPLACE FUNCTION your_function_name(table_name VARCHAR, fields VARCHAR, filters VARCHAR) RETURNS SETOF RECORD AS $$ DECLARE table_join VARCHAR(2000) := ''; filter VARCHAR(2000) := ''; where_filters VARCHAR(2000) := ''; v_join INTEGER; v_count INTEGER; v_filter_table VARCHAR; v_q VARCHAR; v_in INTEGER; v_where VARCHAR; BEGIN v_q := ''; v_join := strpos(SUBSTRING(filters, 1, strpos(filters, '=') - 1), '.'); IF v_join > 0 THEN -- 替代countCharsInSentence统计逗号数量 v_count := LENGTH(filters) - LENGTH(REPLACE(filters, ',', '')); IF v_count = 0 THEN v_count := 1; END IF; LOOP filter := split_part(filters, ',', v_count); where_filters := where_filters || ',' || UPPER(LEFT(filter, 1)) || SUBSTRING(filter, 2); v_filter_table := split_part(filter, '.', 1); IF v_filter_table != '' THEN v_filter_table := UPPER(LEFT(v_filter_table, 1)) || SUBSTRING(v_filter_table, 2); table_join := table_join || ' ' || table_name || ' JOIN ' || v_filter_table || ' ON(' || table_name || '.id = ' || v_filter_table || '.idRef) '; END IF; v_count := v_count - 1; EXIT WHEN v_count <= 0; END LOOP; filters := SUBSTRING(where_filters, 2); IF fields IS NOT NULL AND fields != '' THEN v_q := 'SELECT id, ' || fields || ' FROM ' || table_join || ' WHERE '; ELSE v_q := 'SELECT ' || table_name || '.* FROM ' || table_join || ' WHERE '; END IF; ELSE IF fields IS NOT NULL AND fields != '' THEN v_q := 'SELECT id, ' || fields || ' FROM ' || table_name || ' WHERE '; ELSE v_q := 'SELECT * FROM ' || table_name || ' WHERE '; END IF; END IF; v_in := strpos(filters, ' IN ('); IF v_in > 0 THEN v_where := filters; ELSIF filters IS NOT NULL AND filters != '' THEN v_where := REPLACE(filters, '=', '=''') || ''''; v_where := REPLACE(v_where, ',', ''' AND '); ELSE v_where := '1=1'; END IF; v_q := v_q || v_where; v_q := REPLACE(v_q, ';', ';'); -- 执行动态查询并返回结果 RETURN QUERY EXECUTE v_q; END; $$ LANGUAGE plpgsql;
内容的提问来源于stack exchange,提问作者Samuel Josh
相关产品推荐
相关产品推荐

