Postgres 从动态 sql 字符串创建本地临时表(在提交删除时)

Posted

技术标签:

【中文标题】Postgres 从动态 sql 字符串创建本地临时表(在提交删除时)【英文标题】:Postgres creating a local temp table (on commit drop) from a dynamic sql string 【发布时间】:2012-08-31 14:48:57 【问题描述】:

我有一个在 postgres UDF 中生成的查询字符串,我想把它的结果放在一个临时表中以执行连接(我正在使用 LIMITOFFSET,我不想加入其他 ttables 只是为了最终切断数据——即查询计划中的 LIMIT 运算符)。我尝试使用以下语句创建临时表。

CREATE LOCAL TEMP TABLE query_result ON COMMIT DROP AS EXECUTE query_string_;

但我收到以下错误通知:

********** Error **********

ERROR: prepared statement "query_string_" does not exist
SQL state: 26000
Context: SQL statement "CREATE LOCAL TEMP TABLE query_result ON COMMIT DROP AS EXECUTE query_string_"
PL/pgSQL function "search_posts_unjoined" line 48 at SQL statement

另外,我尝试准备语句,但我也无法正确使用语法。

有问题的 UDF 是:

CREATE OR REPLACE FUNCTION search_posts_unjoined(
    forum_id_ INTEGER,
    query_    CHARACTER VARYING,
    offset_ INTEGER DEFAULT NULL,
    limit_ INTEGER DEFAULT NULL,
    from_date_ TIMESTAMP WITHOUT TIME ZONE DEFAULT NULL,
    to_date_ TIMESTAMP WITHOUT TIME ZONE DEFAULT NULL,
    in_categories_ INTEGER[] DEFAULT ''
    )
RETURNS SETOF forum_posts AS $$
DECLARE
    join_string CHARACTER VARYING := ' ';
    from_where_date CHARACTER VARYING := ' ';
    to_where_date CHARACTER VARYING := ' ';
    query_string_ CHARACTER VARYING := ' ';
    offset_str_ CHARACTER VARYING := ' ';
    limit_str_ CHARACTER VARYING := ' ';
BEGIN
    IF NOT from_date_ IS NULL THEN
        from_where_date := ' AND fp.posted_at > ''' || from_date_ || '''';
    END IF;

    IF NOT to_date_ IS NULL THEN
        to_where_date := ' AND fp.posted_at < ''' || to_date_ || '''';
    END IF;

    IF NOT offset_ IS NULL THEN
        offset_str_ := ' OFFSET ' || offset_; 
    END IF;

    IF NOT limit_ IS NULL THEN
        limit_str_ := ' LIMIT ' || limit_;
    END IF;

    IF NOT limit_ IS NULL THEN
    END IF;

    CREATE LOCAL TEMP TABLE un_cat(id) ON COMMIT DROP AS (select * from unnest(in_categories_)) ;

    if in_categories_ != '' THEN
        join_string := ' INNER JOIN un_cat uc ON uc.id = fp.category_id ' ;
    END IF;

    query_string_ := '
    SELECT fp.*
    FROM forum_posts fp' ||
        join_string
    ||
    'WHERE fp.forum_id = ' || forum_id_ || ' AND
    to_tsvector(''english'',fp.post_text) @@ to_tsquery(''english'','''|| query_||''')' || 
        from_where_date || 
        to_where_date ||
        offset_str_ ||
        limit_str_ 
    ||  ';';

    CREATE LOCAL TEMP TABLE query_result ON COMMIT DROP AS EXECUTE query_string_;

    RAISE NOTICE '%', query_string_;

    RETURN QUERY
    EXECUTE query_string_;
END;
$$ LANGUAGE plpgsql;

当相关语句被删除时它会起作用。

【问题讨论】:

【参考方案1】:

改用:

EXECUTE '
CREATE TEMP TABLE query_result ON COMMIT DROP AS '|| query_string_;

EXECUTE 整个声明。CREATE TABLE foo AS EXECUTE &lt;query&gt; 的语法形式无效。

LOCAL 只是一个干扰词,在这种情况下会被忽略。

更多details in the manual.

【讨论】:

啊,“间接级别”的乐趣 =D 非常感谢。

以上是关于Postgres 从动态 sql 字符串创建本地临时表(在提交删除时)的主要内容,如果未能解决你的问题,请参考以下文章

postgres中的动态sql查询

Postgres 中的动态 SQL

在 Python 中从字符串数组(或元组)创建动态 sql“in list”子句的“最佳”方法是啥? [复制]

SQL - Postgres 字符串 agg 给出重复项

如何在 postgres 中创建表并插入具有动态值的数据

无法从 GKE 中的 pod 内部连接到 Postgres SQL 实例