【问题标题】:Merge multiple result tables and perform final query on result合并多个结果表并对结果执行最终查询
【发布时间】:2015-10-11 10:59:30
【问题描述】:

我有一个函数返回表,它将多次调用的输出累积到另一个函数返回表。我想在返回结果之前对构建的表执行最终查询。目前我将其实现为两个函数,一个累积,一个执行最终查询,这很难看:

CREATE OR REPLACE FUNCTION func_accu(LOCATION_ID INTEGER, SCHEMA_CUSTOMER TEXT)
  RETURNS TABLE("networkid" integer, "count" bigint) AS $$
DECLARE
GATEWAY_ID integer;
BEGIN
    FOR GATEWAY_ID IN
        execute format(
            'SELECT id FROM %1$I.gateway WHERE location_id=%2$L'
           , SCHEMA_CUSTOMER, LOCATION_ID)
    LOOP
        RETURN QUERY execute format(
            'SELECT * FROM get_available_networks_gw(%1$L, %2$L)'
           , GATEWAY_ID, SCHEMA_CUSTOMER);
    END LOOP;
END;
$$ LANGUAGE plpgsql;


CREATE OR REPLACE FUNCTION func_query(LOCATION_ID INTEGER, SCHEMA_CUSTOMER TEXT)
  RETURNS TABLE("networkid" integer, "count" bigint) AS $$
DECLARE
BEGIN
    RETURN QUERY execute format('
       SELECT networkid, max(count) FROM func_accu(%2$L, %1$L) GROUP BY networkid;'
     , SCHEMA_CUSTOMER, LOCATION_ID);
END;
$$ LANGUAGE plpgsql;

如何在单个函数中优雅地做到这一点?

【问题讨论】:

  • 请记住始终提供您的 Postgres 版本和必要的上下文 - 至少要提供 get_available_networks_gw(..) 的确切结果类型

标签: postgresql parameter-passing aggregate-functions plpgsql dynamic-sql


【解决方案1】:

两个函数都被简化和合并,还在USING clause中提供value参数:

CREATE OR REPLACE FUNCTION pg_temp.func_accu(_location_id integer, schema_customer text)
  RETURNS TABLE(networkid integer, count bigint) AS
$func$
BEGIN
   RETURN QUERY EXECUTE format('
      SELECT f.networkid, max(f.ct)
      FROM   %I.gateway g
           , get_available_networks_gw(g.id, $1) f(networkid, ct)
      WHERE  g.location_id = $2
      GROUP  BY 1'
    , _schema_customer)
   USING  _schema_customer, _location_id;
END
$func$ LANGUAGE plpgsql;

呼叫:

SELECT * FROM func_accu(123, 'my_schema');

相关:

我正在使用函数返回的列的别名 (f(networkid, ct)),因为您没有透露 get_available_networks_gw() 的返回类型。可以直接使用返回类型的列名。

FROM 子句中的逗号 (,) 是 CROSS JOIN LATERAL ... 的简短语法。需要 Postgres 9.3 或更高版本

或者你可以运行这个查询而不是函数:

SELECT f.networkid, max(f.ct)
FROM   myschema.gateway g, get_available_networks_gw(g.id, 'my_schema') f(networkid, ct)
WHERE  g.location_id = $2
GROUP  BY 1;

【讨论】:

  • 谢谢您,您的解决方案非常完美且解释清楚!