Ale*_*ber 9 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)
Run Code Online (Sandbox Code Playgroud)
并且有一张桌子可以控制该游戏的玩家分数#321:
# select * from pref_scores where gid=321;
id | gid | money | quit
----------------+-----+-------+------
OK531282114947 | 321 | 218 | f
OK501857527071 | 321 | -156 | f
OK429671947957 | 321 | -62 | f
Run Code Online (Sandbox Code Playgroud)
当我在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)
Run Code Online (Sandbox Code Playgroud)
但是当我尝试创建我的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;
Run Code Online (Sandbox Code Playgroud)
错误:
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
Run Code Online (Sandbox Code Playgroud)
为什么(临时表不允许在这里?)以及保存我要删除的gid临时列表的位置?
(而且我不想使用"删除级联",因为我还没有习惯它,而我的脚本/数据库还没有准备好).
Erw*_*ter 14
除了显式创建临时表然后插入其中之外,还有另一种更简单,正确的方法:CREATE TEMP TABLE AS按照文档中的建议:
此命令在功能上类似于
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;
Run Code Online (Sandbox Code Playgroud)
在现代的Postgres中,上面只对需要使用实际临时表的复杂操作有意义- 例如在继续之前在其上创建索引.
在Postgres 9.1或更高版本中,使用数据修改CTE来处理简单的情况,例如手头的情况:
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;
Run Code Online (Sandbox Code Playgroud)
mu *_*ort 10
您可以创建临时表,然后执行通常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;
Run Code Online (Sandbox Code Playgroud)
如果要复制表的结构,还有一个CREATING TABLE的LIKE选项:
LIKE parent_table [ like_option ... ]
该LIKE子句指定一个表,新表从该表自动复制所有列名,其数据类型及其非空约束.
但我认为你只需要一个临时表来保存一些ID,这可能有点过分.
SELECT INTO在程序之外按预期工作:
[...]这种形式的SELECT INTO在ECPG或PL/pgSQL中不可用,因为它们以不同的方式解释INTO子句.
SELECT INTO用于将SELECT的结果存储在PostgreSQL过程中的局部变量中:
可以将产生单行(可能是多列)的SQL命令的结果分配给记录变量,行类型变量或标量变量列表.这是通过编写基本SQL命令并添加
INTO子句来完成的.
| 归档时间: |
|
| 查看次数: |
22103 次 |
| 最近记录: |