在 PL/pgSQL 过程中使用临时表来清理表
我正在尝试从游戏数据库中删除与用户 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-prompt 上尝试以下 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 的目的被删除?
(而且我不想使用“删除级联”,因为我还不习惯它,而且我的脚本/数据库还没有为此做好准备)。
I'm trying to delete all data related to a user id from a game database.
There is a table holding all games (each played by 3 players):
# select * from pref_games where gid=321;
gid | rounds | finished
-----+--------+----------------------------
321 | 17 | 2011-10-26 17:16:04.074402
(1 row)
And there is a table holding players scores for that game #321:
# select * from pref_scores where gid=321;
id | gid | money | quit
----------------+-----+-------+------
OK531282114947 | 321 | 218 | f
OK501857527071 | 321 | -156 | f
OK429671947957 | 321 | -62 | f
When I try the following SELECT INTO statement on the psql-prompt of PostgreSQL it seems to work as expected (and the temp table disappears when session is closed):
# 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)
But when I try to create my PL/pgSQL procedure I get error:
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;
The error:
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
Why is that (temp tables not allowed here?) and where to save my temp list of the gid's to be deleted?
(And I'd prefer not to use "on delete cascade" because I'm not used to it yet and my scripts/database isn't prepared for that yet).
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
数据修改 CTE
自 Postgres 9.1 使用 数据修改 CTE 适用于简单的情况,例如当前的情况:
临时表
在大多数情况下,您不需要实际临时表。例外情况是临时表上的索引有助于提高性能,或者您需要相同的临时表用于更多用途。
有一种更简单的方法:
CREATE TEMP TABLE AS
正如手册中推荐的:
使用
DELETE .. USING 也会更有效..
而不是子选择。是的,除非您计划在提交事务后在同一会话中使用临时表,否则请添加
ON COMMIT DROP
。将它们放在一起,您的函数可能如下所示:
注意:这不能是普通的 SQL 函数,因为它不能引用仅在同一函数中创建的对象。
Data modifying CTE
Since Postgres 9.1 use data-modifying CTEs for simple cases like the one at hand:
Temp table
In most cases, you don't need an actual temporary table. Exceptions would be when an index on the temp table helps performance, or when you need the same temp table for more purposes.
There is a simpler way to do it:
CREATE TEMP TABLE AS
As recommended in the manual:
It would also be more efficient to use
DELETE .. USING ..
instead of a sub-select.And yes, unless you plan to use the temp table in the same session after the transaction committed, add
ON COMMIT DROP
.Putting it all together, your function could look like this:
Note: this can't be a plain SQL function, because that cannot reference objects that are only created in the same function.
您可以创建临时表,然后将通常的
INSERT ... SELECT
作为单独的操作进行:还有一个 LIKE 选项来创建表 如果你想复制表的结构:
但我认为你只需要一个临时表来保存一些 ID,所以这可能有点矫枉过正。
SELECT INTO
按照您的预期工作外部一个过程:SELECT INTO
用于将 SELECT 的结果存储在局部变量中 在 PostgreSQL 过程内:You could create the temporary table and then do the usual
INSERT ... SELECT
as separate operations:There's also a LIKE option to CREATE TABLE if you want to duplicate a table's structure:
But I think you just need a temporary table to hold some IDs so that's probably overkill.
SELECT INTO
works as you expect outside a procedure:SELECT INTO
is used to store the result of a SELECT in a local variable inside a PostgreSQL procedure:你可以尝试
You can try