我正在尝试从游戏数据库中删除与用户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临时列表的位置?
(而且我不想使用“删除级联”,因为我还没有习惯它,而我的脚本/数据库还没有准备好。)
答案 0 :(得分:14)
除了显式创建临时表然后插入其中之外,还有另一种更简单的 正确 方法: CREATE TEMP TABLE AS
< / strong>为recommended in the docs:
此命令在功能上与
SELECT INTO
类似,但确实如此 因为它不太可能与其他用途混淆SELECT INTO
语法。此外,CREATE TABLE AS
提供了一个超集SELECT INTO
提供的功能。
对于Postgres 9.1或更高版本,请参阅下文。
使用 DELETE .. USING ..
代替子选项也会更有效。
是的,如果您不打算在提交事务后继续使用临时表(在同一会话中),请添加ON 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;
在现代的Postgres中,上述只适用于需要使用实际临时表的复杂操作 - 例如在继续之前在其上创建索引。
在Postgres 9.1或更高版本中使用data-modifying CTEs表示手头的简单案例:
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;
答案 1 :(得分:9)
您可以创建临时表,然后执行通常的INSERT ... SELECT
作为单独的操作:
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 option to CREATE TABLE:
LIKE parent_table [ like_option ... ]
LIKE
子句指定一个表,新表自动从中复制所有列名,数据类型及其非空约束。
但我认为你只需要一个临时表来保存一些ID,这可能有点过分。
SELECT INTO
按预期工作outside a procedure:
[...]这种形式的SELECT INTO在ECPG或PL / pgSQL中不可用,因为它们以不同的方式解释INTO子句。
SELECT INTO
用于将SELECT的结果存储在局部变量inside a PostgreSQL procedure中:
可以将产生单行(可能是多列)的SQL命令的结果分配给记录变量,行类型变量或标量变量列表。这是通过编写基本SQL命令并添加
INTO
子句来完成的。
答案 2 :(得分:1)
你可以尝试
EXECUTE 'create temp table temp_gids AS select from pref_scores where id=$1'
USING _id;