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

PL/pgSQL跨schema执行动态查询 实现未知列数结果存入临时表

PostgreSQL跨多schema动态执行任意查询解决方案

PostgreSQL的PL/pgSQL函数默认要求返回结构静态定义,针对你需要的动态返回列的场景,有两种可行实现方案:


方案1:返回动态记录集(调用时指定结构)

该方案直接返回结果集,调用时需要手动声明返回列的结构:

CREATE OR REPLACE FUNCTION pg_temp.select_all(query text)
RETURNS SETOF RECORD AS $$
DECLARE
    v_schema text;
    v_union_query text := '';
BEGIN
    -- 拼接所有schema的UNION ALL语句
    FOR v_schema IN (
        SELECT schema_name
        FROM information_schema.schemata
        WHERE schema_name IN (SELECT login FROM cdu.nc_tenant)
    ) LOOP
        IF v_union_query <> '' THEN
            v_union_query := v_union_query || ' UNION ALL ';
        END IF;
        v_union_query := v_union_query || format('SELECT %L AS schema, * FROM (%s) AS t', v_schema, query);
    END LOOP;

    -- 返回动态结果集
    RETURN QUERY EXECUTE v_union_query;
END; $$
LANGUAGE plpgsql;

使用示例:

-- 统计sku数量的查询
SELECT * FROM pg_temp.select_all('SELECT count(1) FROM sku') 
AS t(schema text, count bigint);

-- 查询租户变量的查询
SELECT * FROM pg_temp.select_all('SELECT variable, value FROM cdu.nc_tenant_variables where variable = ''theme''')
AS t(schema text, variable text, value text);

方案2:自动生成临时表存储结果(更易用,无需提前指定结构)

该方案会自动创建临时表存储合并后的结果,调用后直接查询临时表即可,不需要提前声明返回结构,更符合你的使用习惯:

CREATE OR REPLACE FUNCTION pg_temp.select_all(query text)
RETURNS VOID AS $$
DECLARE
    v_schema text;
    v_first_schema boolean := true;
    v_temp_table text := 'cross_schema_result';
BEGIN
    -- 先清理已存在的临时表
    EXECUTE format('DROP TABLE IF EXISTS %I', v_temp_table);

    -- 遍历所有符合条件的schema
    FOR v_schema IN (
        SELECT schema_name
        FROM information_schema.schemata
        WHERE schema_name IN (SELECT login FROM cdu.nc_tenant)
    ) LOOP
        IF v_first_schema THEN
            -- 第一个schema的执行结果用来创建临时表结构
            EXECUTE format(
                'CREATE TEMP TABLE %I AS SELECT %L AS schema, * FROM (%s) AS t',
                v_temp_table,
                v_schema,
                query
            );
            v_first_schema := false;
        ELSE
            -- 后续schema的结果直接插入临时表
            EXECUTE format(
                'INSERT INTO %I SELECT %L AS schema, * FROM (%s) AS t',
                v_temp_table,
                v_schema,
                query
            );
        END IF;
    END LOOP;
END; $$
LANGUAGE plpgsql;

使用示例:

-- 执行任意查询
SELECT pg_temp.select_all('SELECT count(1) FROM sku');
-- 直接查询临时表获取合并结果
SELECT * FROM pg_temp.cross_schema_result;

注意事项

  • 所有目标schema执行传入的查询返回的列数量、列类型、列名必须完全一致,否则会执行报错
  • 传入的查询语句中不要包含名为schema的列,避免和首列冲突
  • 如果需要避免SQL注入风险,可以对传入的query参数做额外的合法性校验

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.04 16:06:03