11

ゲームデータベースからユーザー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で次のSELECTINTOステートメントを試してみると、期待どおりに機能しているようです(セッションを閉じると一時テーブルが消えます)。

# 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の一時リストをどこに保存するのですか?

(そして、私はまだそれに慣れておらず、スクリプト/データベースがまだそのために準備されていないので、「カスケードの削除」を使用したくないです)。

4

3 に答える 3

15

一時テーブルを明示的に作成してから挿入する以外に、別の、より簡単で正しい方法があります:ドキュメントで推奨されているよう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;

データ変更 CTE

現代の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;
于 2011-10-29T22:52:14.973 に答える
13

一時テーブルを作成してから、通常の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;

テーブルの構造を複製したい場合は、CREATE TABLE に LIKE オプションもあります。

LIKE parent_table [ like_option ... ]
このLIKE句は、新しいテーブルがすべての列名、それらのデータ型、およびそれらの非 null 制約を自動的にコピーするテーブルを指定します。

しかし、いくつかのIDを保持するための一時テーブルが必要なだけだと思う​​ので、それはおそらくやり過ぎです。

SELECT INTOプロシージャので期待どおりに動作します。

[...] この形式の SELECT INTO は、ECPG または PL/pgSQL では使用できません。これは、INTO 句の解釈が異なるためです。

SELECT INTOSELECT の結果をPostgreSQL プロシージャ内のローカル変数に格納するために使用されます。

単一の行 (場合によっては複数の列) を生成する SQL コマンドの結果は、レコード変数、行型変数、またはスカラー変数のリストに割り当てることができます。これは、基本 SQL コマンドを作成し、INTO句を追加することによって行われます。

于 2011-10-28T18:24:43.167 に答える
1

You can try

EXECUTE 'create temp table temp_gids AS select from pref_scores where id=$1'
    USING _id;
于 2011-10-28T20:13:59.503 に答える