13

これはとても単純なようですが、私はこの質問に対する答えを見つけることができませんでした。

私が欲しいものは?(外部キーを介して)参照されなくなったときに自分自身を削除する行を持つマスターテーブル。ソリューションはPostgreSqlに固有である場合とそうでない場合があります。

どのように?UPDATEこの問題を解決するための私のアプローチの1つ(実際には、これまでのところ唯一のアプローチ)には、次のものが含まれます。行上または行上でこのマスターテーブルを参照するすべてのテーブルについて、マスター内DELETEの参照される行をチェックするために、他の行の数参照されている行を引き続き参照します。ゼロに下がった場合は、マスターのその行も削除します。

(もっと良いアイデアがあれば教えてください!)

詳細: 他の多くの人から参照されている1つのマスターテーブルがあります

CREATE TABLE master (
  id serial primary key,
  name text unique not null
);

他のすべてのテーブルは、通常、同じ形式です。

CREATE TABLE other (
  ...
  master_id integer references master (id)
  ...
);

これらのいずれかがではない場合NULL、それらはの行を参照しmasterます。これに移動して削除しようとすると、すでに参照されているため、エラーメッセージが表示されます。

ERROR:  update or delete on table "master" violates foreign key constraint "other_master_id_fkey" on table "other"
DETAIL:  Key (id)=(1) is still referenced from table "other".
Time: 42.972 ms

を参照するテーブルがたくさんある場合でも、これを理解するのにそれほど時間はかからないことに注意してくださいmaster。エラーを発生させずにこの情報を見つけるにはどうすればよいですか?

4

3 に答える 3

5

次のいずれかを実行できます。

reference_count1)マスターテーブルにフィールドを追加します。詳細テーブルでトリガーを使用すると、これを含む行が追加さreference countれるたびにトリガーが増加します。master_id行が削除されたら、カウントを減らします。reference_count0に達したら-レコードを削除します。

2)pg_constraintテーブル(詳細はこちら)を使用して、参照テーブルのリストを取得し、動的SQLクエリを作成します。

master_id3)メインテーブルで削除するすべての詳細テーブルでトリガーを作成します。を含む無音エラーメッセージBEGIN ... EXCEPTION ... END

于 2013-01-16T11:35:51.087 に答える
3

特定のマスター行を参照する他のすべてのテーブルの実際の行数が必要な場合に備えて、PL/pgSQLをいくつか示します。これは、単一列の制約がある単純なケースで機能することに注意してください。複数列の制約にさらに関与します。

CREATE OR REPLACE FUNCTION count_references(master regclass, pkey_value integer,
    OUT "table" regclass, OUT count integer)
    RETURNS SETOF record 
    LANGUAGE 'plpgsql'
    VOLATILE 
AS $BODY$
declare
  x record;           -- constraint info for each table in question that references master
  sql text;           -- temporary buffer
begin
  for x in
    select conrelid, attname
    from pg_constraint
    join pg_attribute on conrelid=attrelid and attnum=conkey[1]
    where contype='f' and confrelid=master
      and confkey=( -- here we assume that FK references master's PK
        select conkey
        from pg_constraint
        where conrelid=master and contype='p'
      )
  loop
    "table" = x.conrelid;
    sql = format('select count(*) from only %s where %I=$1', "table", x.attname);
    execute sql into "count" using pkey_value;
    return next;
  end loop;
end
$BODY$;

次に、次のように使用します

select * from count_references('master', 1) where count>0

これにより、id=1のマスターテーブルへの参照を持つテーブルのリストが返されます。

于 2020-01-27T05:17:32.123 に答える
-1
SELECT * 
FROM master ma
WHERE EXISTS (
    SELECT *
    FROM other ot
    WHERE ot.master_id = ma.id
    );

または、その逆:

SELECT * 
FROM other ot
WHERE EXISTS (
    SELECT *    
    FROM master ma
    WHERE ot.master_id = ma.id
    );

したがって、によって参照されていないマスターの行のみを更新(または削除)するother場合は、次のことができます。

UPDATE master ma
SET id = 1000+id
  , name = 'blue'
WHERE name = 'green'
AND NOT EXISTS (
    SELECT *
    FROM other ot
    WHERE ot.master_id = ma.id
    );
于 2013-01-16T11:24:29.393 に答える