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

时间:2015-09-19 08:17:21

标签: sql postgresql plpgsql

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

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

是否有像

这样的东西
external table (kuupaev date)

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

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

或者f_createquery应该创建具有固定名称tehing的临时表吗?

2 个答案:

答案 0 :(得分:2)

如果In [15]: import pandas as pd In [16]: df = pd.DataFrame([['67:01'],['11:11'],['59:59'],['09:08']],columns=['Used']) In [17]: df Out[17]: Used 0 67:01 1 11:11 2 59:59 3 09:08 In [18]: import datetime In [19]: df.Used.apply(lambda x: datetime.timedelta(minutes=int(x.split(':')[0]), seconds=int(x.split(':')[1]))) Out[19]: 0 01:07:01 1 00:11:11 2 00:59:59 3 00:09:08 Name: Used, dtype: timedelta64[ns] 生成临时表df.Used.apply(lambda x: float(x.split(':')[0]) + float(x.split(':')[1])/60) ,则它不应返回任何内容。您的功能应如下所示:

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;

不会工作,因为你因CTE而重新宣布plpgsql。相反,with tehing as ( select * from f_createquery() _ ) select * from f_usequery() _ 适用于tehing临时表,您可以从中选择或使用f_usequery()的结果进行进一步分析:

tehing

答案 1 :(得分:0)

简单案例: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';

它会在搜索路径中找到名为“tehing”的任何表。但您只对存在该名称的临时表感兴趣。默认情况下,临时模式首先位于搜索路径中:

相关: