0

我有一个存储过程RETURNS record

CREATE OR REPLACE FUNCTION r_rpt_prov_summary() 
RETURNS record 
AS $$ 
  DECLARE
    _fields             record;
  BEGIN
    SELECT INTO _fields
      0::integer AS customers,
      0::integer AS customers_active;

    SELECT INTO _fields.customers count(*) FROM customer;
    SELECT INTO _fields.customers_active count(*) FROM customer WHERE active = 't';

    RETURN _fields;
  END
$$ LANGUAGE 'plpgsql';

但是,为了查询它,我必须显式枚举返回的列和类型:

SELECT * FROM r_rpt_prov_summary() AS (a integer, b integer);

为了使这个对 MVC 框架来说是可口的,它本质上想要查询表,我将它包装在一个SQL函数中RETURNS TABLE

CREATE OR REPLACE FUNCTION rpt_prov_summary() 
RETURNS TABLE (
        customers               integer,
        customers_active        integer
) AS $$
  SELECT * FROM r_rpt_prov_summary() AS (customers integer, customers_active integer);
$$ LANGUAGE 'sql';

只要这两个函数驻留在相同的模式或search_path空间中,这就会非常有效。但是,在这种情况下,他们生活在自己的非标准模式中,所以我必须将外部函数查询为myschema.rpt_prov_summary(),即

SELECT * FROM myschema.rpt_prov_summary();

如果我的架构和搜索路径设置为:这不起作用public

test=> SELECT * FROM myschema.rpt_prov_summary();
ERROR:  function r_rpt_prov_summary() does not exist
LINE 2:   SELECT * FROM r_rpt_prov_summary() AS (customers integer, ...
                        ^
HINT:  No function matches the given name and argument types. You might need to add explicit type casts.

自然,您的想法会转向调用SET SCHEMA 'myschema'SET search_path TO myschema查询执行之前。我的也是。问题是它不适用于我打电话的环境。MVC 框架使用准备好的语句来构造查询,而 PostgreSQL 不赞成这样的事情:

SET search_path TO myschema;SELECT * FROM rpt_prov_summary();

也就是说:

< 2016-03-14 20:50:46.410 EDT >ERROR: cannot insert multiple commands into a prepared statement

所以,这是行不通的。将模式作为外部函数的参数提供也不起作用;我只是在 MVC 框架的约束下没有那种灵活性,它想要查询普通的旧表或像表一样的东西。

current_schema标识客户端会话的当前模式,因此这无济于事。已经尝试过这个:

CREATE OR REPLACE FUNCTION rpt_prov_summary() 
RETURNS TABLE (
    customers       integer,
    customers_active    integer
) AS $$
  BEGIN
    RAISE NOTICE 'Current schema: %', current_schema;
    RETURN QUERY EXECUTE 'SELECT * FROM ' || current_schema || '.r_rpt_prov_summary() AS (customers integer, customers_active integer)';
  END
$$ LANGUAGE 'plpgsql';

没有骰子 - Current schema: public,正如预期的那样。

有没有办法以某种方式捕获外部调用的模式空间并将其传播到封装的查询中?

4

1 回答 1

2

1.

我有一个存储过程...

不,你没有。你有一个功能,它几乎但不完全相同。Postgres 目前不支持存储过程。

2.

从根本上简化。不要使用两个嵌套函数,而是使用一个带OUT参数的简单 SQL 函数:

CREATE OR REPLACE FUNCTION myschema.r_rpt_prov_summary(  -- schema-qualify!
          OUT _customers integer
        , OUT _customers_active integer) AS
$func$
   SELECT count(*)::int
        , count(*) FILTER (WHERE active)::int  -- requires Postgres 9.4+
   FROM   myschema.customer;                   -- schema-qualify!
$func$ LANGUAGE sql;                           -- don't quote the language name

称呼:

SELECT * FROM myschema.rpt_prov_summary();

独立于您当前的search_path设置工作。

注意RETURNS TABLE()我的版本RETURNS record也是0 - n 行RETURNS record

3.

可以通过search_path许多不同的方式设置,甚至作为函数本身的本地设置 - 如有必要:

要回答您的实际问题

有没有办法以某种方式捕获外部调用的模式空间并将其传播到封装的查询中?

CREATE OR REPLACE FUNCTION myschema.r_rpt_prov_summary(OUT _customers integer
                                                     , OUT _customers_active integer) AS 
$func$ 
BEGIN
   SELECT INTO _customers, _customers_active
          count(*)::int, count(*) FILTER (WHERE active)::int  
   FROM   customer;  -- no schema-qualification
END
$func$  LANGUAGE plpgsql;

CREATE OR REPLACE FUNCTION myschema.rpt_prov_summary() 
  RETURNS TABLE (customers int, customers_active int) AS
$func$
   SELECT * FROM myschema.r_rpt_prov_summary();
$func$ LANGUAGE sql SET search_path = myschema;  -- set the search_path here

search_path传播到嵌套函数 - 正是您正在寻找的。

或者只是无处不在的模式限定标识符(包括函数名称)是明确的。

于 2016-03-15T03:53:31.277 回答