Postgresql 在PL/pgSQL过程中使用临时表清理表

Postgresql 在PL/pgSQL过程中使用临时表清理表,postgresql,plpgsql,select-into,Postgresql,Plpgsql,Select Into,我正在尝试从游戏数据库中删除与用户id相关的所有数据 有一张桌子,上面有3名玩家玩的所有游戏: # select * from pref_games where gid=321; gid | rounds | finished -----+--------+---------------------------- 321 | 17 | 2011-10-26 17:16:04.074402 (1 row) 还有一张桌子,上面有321场比赛的球员得分: # selec

我正在尝试从游戏数据库中删除与用户id相关的所有数据

有一张桌子,上面有3名玩家玩的所有游戏:

# select * from pref_games where gid=321;
 gid | rounds |          finished
-----+--------+----------------------------
 321 |     17 | 2011-10-26 17:16:04.074402
(1 row)
还有一张桌子,上面有321场比赛的球员得分:

# select * from pref_scores where gid=321;
      id       | gid | money | quit
----------------+-----+-------+------
 OK531282114947 | 321 |   218 | f
 OK501857527071 | 321 |  -156 | f
 OK429671947957 | 321 |   -62 | f
当我在PostgreSQL的psql提示符上尝试以下SELECT INTO语句时,它似乎按预期工作,并且在会话关闭时临时表消失:

# select gid into temp temp_gids from pref_scores where id='OK446163742289';
SELECT

# select * from temp_gids ;
 gid
------
 1895
 1946
 1998
 2094
 2177
 2215
(6 rows)
但当我尝试创建PL/pgSQL过程时,我得到一个错误:

    create or replace function pref_delete_user(_id varchar)
        returns void as $BODY$
            begin

            select gid into temp temp_gids from pref_scores where id=_id;
            delete from pref_scores where gid in
                (select gid from temp_gids);
            delete from pref_games where gid in
                (select gid from temp_gids);

            delete from pref_rep where author=_id;
            delete from pref_rep where id=_id;

            delete from pref_catch where id=_id;
            delete from pref_game where id=_id;
            delete from pref_hand where id=_id;
            delete from pref_luck where id=_id;
            delete from pref_match where id=_id;
            delete from pref_misere where id=_id;
            delete from pref_money where id=_id;
            delete from pref_pass where id=_id;
            delete from pref_status where id=_id;
            delete from pref_users where id=_id;

            end;
    $BODY$ language plpgsql;
错误:

ERROR:  syntax error at "temp"
DETAIL:  Expected record variable, row variable, or list of scalar variables following INTO.
CONTEXT:  compilation of PL/pgSQL function "pref_delete_user" near line 3
为什么这里不允许临时表格?在哪里保存要删除的gid临时列表


我不喜欢在delete cascade上使用,因为我还不习惯它,而且我的脚本/数据库还没有准备好。。。选择作为单独的操作:

create temporary table temp_gids (gid int not null) on commit drop;
insert into temp_gids (gid) select gid from pref_scores where id = _id;
如果要复制表的结构,还有一个选项:

LIKE parent_表[LIKE_选项…] LIKE子句指定一个表,新表从中自动复制所有列名、它们的数据类型以及它们的NOTNULL约束

但我认为你只需要一个临时的桌子来存放一些ID,所以这可能太过分了

如您所料,选择进入工作:

[…]这种形式的SELECT INTO在ECPG或PL/pgSQL中不可用,因为它们对INTO子句的解释不同

SELECT INTO用于将SELECT的结果存储在局部变量中:

SQL命令生成一行(可能包含多列)的结果可以分配给记录变量、行类型变量或标量变量列表。这是通过编写基本SQL命令并添加INTO子句来完成的

你可以试试

EXECUTE 'create temp table temp_gids AS select from pref_scores where id=$1'
    USING _id;

除了显式创建一个临时表并插入其中之外,还有另一种更简单、正确的方法:创建临时表,如下所示:

此命令在功能上类似于SELECT INTO,但它是 首选,因为它不太可能与 将SELECT转换为语法。此外,createtableas提供了一个超集 由SELECT INTO提供的功能的一部分

对于Postgres 9.1或更高版本,请参见下文

它也将更有效地使用,而不是一个子选择。 是的,如果您不打算在事务提交后在同一会话中继续使用temp表,请添加COMMIT DROP

综上所述,您的函数可能如下所示:

CREATE OR REPLACE FUNCTION pref_delete_user(_id varchar)
  RETURNS void AS
$func$
BEGIN    
   CREATE TEMP TABLE tmp_gids ON COMMIT DROP AS
   SELECT gid FROM pref_scores WHERE id = _id;

   DELETE FROM pref_scores p
   USING  tmp_gids t
   WHERE  p.gid = t.gid;

   DELETE FROM pref_games p
   USING  tmp_gids t
   WHERE  p.gid = t.gid;

   -- more deletes ...    
END
$func$ LANGUAGE plpgsql;
数据修改CTE 在现代的Postgres中,上述内容仅适用于需要使用实际临时表的复杂操作,例如,在继续操作之前在其上创建索引

在Postgres 9.1或更高版本中,用于简单案例,如手头的案例:

   WITH gids AS (SELECT gid FROM pref_scores WHERE id = _id)
      , d1   AS (  
      DELETE FROM pref_scores p
      USING  gids t
      WHERE  p.gid = t.gid
      (
      -- more work using gids?
   DELETE FROM pref_games p
   USING  gids t
   WHERE  p.gid = t.gid;

SELECT INTO在plpgsql中有不同的含义。是的,谢谢,那么在这里使用什么呢?谢谢!在我的过程中创建临时表时,我是否需要在提交时删除?@Alexander:没关系,但是如果你正在进行一系列清理,并且不想让工作半途而废,那么你可能希望将该过程的内脏打包到一个事务中,而这可能是你无论如何都想做的。@muistoshort将该过程的内脏打包到一个事务中是什么意思事务?@muistooshort:函数体始终作为事务执行:要么全部成功,要么全部失败。不需要显式的事务。@Alexander:你可能对我刚才和Erwin关于事务的来来回回感兴趣。我现在想说是的,您可能确实希望在临时表上进行COMMIT DROP。我只想提到,我在postgres 8.3上看到了使用ID数组而不是临时表的显著性能优势。类似于deleter_id=arrayselect id from。。。哪里从tbl中删除,其中gid=ANYdeleter\u id;