【问题标题】:How to use query created in stored procedure in other procedure如何在其他过程中使用在存储过程中创建的查询
【发布时间】:2015-09-19 08:17:21
【问题描述】:

sql 过程创建临时表,该表应该在其他 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

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

有没有类似的东西

external table (kuupaev date)

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

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

或者 f_createquery 应该使用固定名称创建临时表吗?

【问题讨论】:

  • f_createquery() 创建tehing 临时表?您至少可以显示创建临时表的存储过程部分吗?

标签: sql postgresql plpgsql


【解决方案1】:

如果f_createquery() 生成临时表tehing,那么它不应该返回任何东西。您的函数应如下所示:

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

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;

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

您还可以整合这两个函数,这样您就可以调用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 临时表一起使用,您可以从中选择或使用 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';

【讨论】:

  • f_usequery() 如果 tehin 表不存在,则创建会引发错误。如何创建一次 f_usequery() 并仅在以后使用它?是否应该在创建 f_usequery() 之前创建虚拟表格以避免创建错误?
  • 您可以通过测试临时表的存在来将f_createquery() 整合到f_usequery() 中。查看更新的答案。
【解决方案2】:

简单案例:CTE

如果您可以在一个单个 查询中完成所有操作,那么您通常根本不需要临时表或函数。 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;

如果您需要临时表

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

尝试创建临时表:

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

如果表已经存在,你会得到一个错误,这也很好。
然后使用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';

它会在搜索路径中找到名为“tehin”的任何表。但您只对存在该名称的 临时 表感兴趣。默认情况下,临时架构在搜索路径的第一位:

相关:

【讨论】:

    猜你喜欢
    • 2011-03-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-03-02
    • 1970-01-01
    • 1970-01-01
    • 2021-10-30
    • 1970-01-01
    相关资源
    最近更新 更多