如何在其他过程中使用在存储过程中创建的查询

How to use query created in stored procedure in other procedure

sql 过程创建临时 table 应该在其他 sql 过程中使用。 我试过了

CREATE or replace FUNCTION f_createquery()
  RETURNS TABLE ( kuupaev date
   ) AS $f_createquery$

-- actually this is big and time consuming select statement which should evaluated only once:
select current_date as kuupaev
$f_createquery$ LANGUAGE sql STABLE;


CREATE or replace FUNCTION f_usequery()
  RETURNS TABLE ( kuupaev date
  ) AS $f_usequery$

-- big query tehing is used several times in query:
select kuupaev from tehing
union all
select kuupaev+1 from tehing
union all
select kuupaev+2 from tehing
$f_usequery$ LANGUAGE sql STABLE;


with tehing as (
 select * from f_createquery() _
 )

 select * from f_usequery() _

但出现错误

ERROR:  relation "tehing" does not exist

tehing 包含由存储过程创建的临时数据,它不存在于数据库中。如何让其他存储过程使用它? 如何为 Postgres 9.1+ 修复它?

有没有类似的

external table (kuupaev date)

哪个允许定义外部table? 在实际应用中 select f_createquery 中的语句很大且耗时,应该只评估一次。

select * from tehing 替换为 f_usequery() 中的动态 sql 可能有效,但这会阻止程序在 运行 时编译。是否有更好的解决方案或可以更好地传递给其他存储过程,e.q。喜欢参数 ?

或者 f_createquery 是否应该使用固定名称 tehing 创建临时 table?

如果 f_createquery() 产生临时 table tehing 那么它不应该 return 任何东西。您的函数应如下所示:

CREATE FUNCTION f_createquery() RETURNS void AS $f_createquery$
  CREATE TEMPORARY TABLE tehing AS
    SELECT current_date AS kuupaev;  -- complex query here
$f_createquery$ LANGUAGE sql STABLE;

然后您可以在当前会话中使用 tehing table ,就像使用其他 table:

CREATE FUNCTION f_usequery() RETURNS TABLE (kuupaev date) AS $f_usequery$
  SELECT kuupaev FROM tehing
  UNION ALL
  SELECT kuupaev+1 FROM tehing
  UNION ALL
  SELECT kuupaev+2 FROM tehing;
$f_usequery$ LANGUAGE sql STABLE;

请注意,临时 table 在会话结束时被删除。

您还可以集成这 2 个函数,这样您就可以调用 f_usequery() 而不必担心先调用另一个函数:

CREATE FUNCTION f_usequery() RETURNS TABLE (kuupaev date) AS $f_usequery$
BEGIN
  PERFORM 1 FROM information_schema.tables WHERE table_name = 'tehing';
  IF NOT FOUND THEN  -- temp table tehing does not exist
    CREATE TEMPORARY TABLE tehing AS
      SELECT current_date AS kuupaev; -- etc, etc
  END IF;

  RETURN QUERY
    SELECT kuupaev FROM tehing
    UNION ALL
    SELECT kuupaev+1 FROM tehing
    UNION ALL
    SELECT kuupaev+2 FROM tehing;
END; $f_usequery$ LANGUAGE plpgsql STABLE;

请注意,这现在是一个 plpgsql 函数,因此语法略有不同。

结构

with tehing as (
 select * from f_createquery() _
)
select * from f_usequery() _

将不起作用,因为您重新声明 tehing 作为 CTE 的结果。相反,f_usequery()tehing 临时 table 一起工作,您可以从中 select 或对 f_usequery():

的结果进行进一步分析
SELECT f_createquery(); -- this creates the tehing temporary table

SELECT * FROM f_usequery(); -- this operates on the tehing table and returns some results

SELECT *
FROM tableX
JOIN f_usequery() USING (kuupaev)
WHERE kuupaev < '2015-09-19';

简单案例:CTE

如果您可以在 单个 查询中完成所有操作,您通常根本不需要临时 table 或函数。 CTE 完成工作:

WITH tehing AS (
   SELECT current_date AS kuupaev  -- expensive query here
   )
SELECT kuupaev FROM tehing
UNION ALL
SELECT kuupaev+1 FROM tehing
UNION ALL
SELECT kuupaev+2 FROM tehing;

如果你需要临时工 table

临时 table 仅当您确实需要 运行 使用昂贵查询的结果进行多次查询时才有意义。或者,如果您需要在 table 或其他内容上创建索引。

尝试创建临时文件 table:

CREATE TEMP TABLE tehing AS
SELECT current_date AS kuupaev;  -- expensive query here

如果 table 已经存在,你会得到一个错误,这也没关系。
然后 运行 您的查询使用 tehing.

如果你真的需要一个避免这个错误的函数(我对此表示怀疑):

CREATE FUNCTION f_create_tbl()
  RETURNS text AS
$func$
BEGIN
   IF to_regclass('pg_temp.tehing') IS NULL THEN  -- temp table does not exist
      CREATE TEMP TABLE tehing AS
      SELECT current_date AS kuupaev;  -- expensive query here

      RETURN 'Temp table "tehing" created.';
   ELSE
      RETURN 'Temp table "tehing" already exists';
   END IF;
END
$func$ LANGUAGE plpgsql;

通话:

SELECT f_create_tbl();

函数无法声明 STABLE,它是一个 VOLATILE 函数(默认)。

像这样的测试会略微不准确:

PERFORM 1 FROM information_schema.tables WHERE table_name = 'tehing';

它会在搜索路径中找到名为 "tehing" 的 any table。但是您只对存在该名称的 temporary table 感兴趣。默认情况下,临时模式在搜索路径中排在第一位:

  • How does the search_path influence identifier resolution and the "current schema"

相关:

  • How to check if a table exists in a given schema