通过创建存储过程,统计数据库中所有用户表的行数。
CREATE OR REPLACE FUNCTION count_all_tables()
RETURNS TABLE (table_name TEXT, exact_rows BIGINT) AS $$
DECLARE
cur REFCURSOR;
qry TEXT;
tbl TEXT;
cnt BIGINT;
BEGIN
OPEN cur FOR
SELECT FORMAT(
'SELECT %L::TEXT, COUNT(*)::BIGINT FROM %I.%I',
relname,
schemaname,
relname
)
FROM pg_stat_user_tables
WHERE schemaname NOT IN ('pg_catalog', 'information_schema');
LOOP
FETCH cur INTO qry;
EXIT WHEN NOT FOUND;
BEGIN
EXECUTE qry INTO tbl, cnt;
table_name := tbl;
exact_rows := cnt;
RETURN NEXT;
EXCEPTION WHEN others THEN
RAISE WARNING '跳过表: %', SQLERRM;
END;
END LOOP;
CLOSE cur;
END;
$$ LANGUAGE plpgsql;
SELECT * FROM count_all_tables();
函数解析
这个函数是一个 PostgreSQL 存储过程,用于统计数据库中所有用户表的行数。下面我将详细解释这个函数的各个部分:
函数定义
CREATE OR REPLACE FUNCTION count_all_tables()
RETURNS TABLE (table_name TEXT, exact_rows BIGINT) AS $$
CREATE OR REPLACE FUNCTION
:创建或替换一个函数count_all_tables()
:函数名称RETURNS TABLE (table_name TEXT, exact_rows BIGINT)
:定义返回一个结果集,包含两列:表名(TEXT类型)和精确行数(BIGINT类型)
变量声明
DECLARE
cur REFCURSOR; -- 游标变量,用于遍历查询结果
qry TEXT; -- 存储动态生成的SQL查询
tbl TEXT; -- 临时存储表名
cnt BIGINT; -- 临时存储行数
主逻辑
1. 打开游标
OPEN cur FOR
SELECT FORMAT(
'SELECT %L::TEXT, COUNT(*)::BIGINT FROM %I.%I',
relname,
schemaname,
relname
)
FROM pg_stat_user_tables
WHERE schemaname NOT IN ('pg_catalog', 'information_schema');
这部分代码:
- 从系统视图
pg_stat_user_tables
获取所有用户表(排除系统表) - 使用
FORMAT
函数为每个表生成一个计数查询 %L
和%I
是格式占位符,%L
用于字符串字面量,%I
用于标识符(如表名)- 生成的查询形如:
SELECT '表名'::TEXT, COUNT(*)::BIGINT FROM 模式名.表名
2. 循环处理每个表
LOOP
FETCH cur INTO qry; -- 从游标获取下一条记录
EXIT WHEN NOT FOUND; -- 如果没有更多记录则退出循环
BEGIN
EXECUTE qry INTO tbl, cnt; -- 执行动态SQL
table_name := tbl; -- 设置返回的表名
exact_rows := cnt; -- 设置返回的行数
RETURN NEXT; -- 返回当前行
EXCEPTION WHEN others THEN
RAISE WARNING '跳过表: %', SQLERRM; -- 如果出错则跳过并记录警告
END;
END LOOP;
3. 清理资源
CLOSE cur; -- 关闭游标
函数调用
SELECT * FROM count_all_tables();
调用该函数会返回一个结果集,包含数据库中所有用户表的名称和行数。
功能总结
这个函数的主要功能是:
- 查询数据库中所有用户表(排除系统表)
- 为每个表动态生成并执行一个COUNT(*)查询
- 返回表名和对应的行数
- 如果某个表无法统计(如权限问题),会跳过并记录警告而不是终止整个操作
这种动态SQL技术在处理需要遍历多个表的场景中非常有用,特别是在需要获取数据库元信息或执行批量操作时。