6

このような構造を考えると:

CREATE TABLE reference_table (
  reference_table_key numeric NOT NULL,
  reference_value numeric,
  CONSTRAINT reference_table_pk PRIMARY KEY (reference_table_key)
);

CREATE TABLE other_table (
  other_table_key numeric NOT NULL,
  reference_table_key numeric,
  CONSTRAINT other_table_pk PRIMARY KEY (other_table_key),
  ONSTRAINT other_table_reference_fk FOREIGN KEY (reference_table_key)
      REFERENCES reference_table (reference_table_key) MATCH SIMPLE
      ON UPDATE NO ACTION ON DELETE SET NULL
);

CREATE TABLE another_table (
  another_table_key numeric NOT NULL,
  do_stuff_key numeric,
  CONSTRAINT another_table_pk PRIMARY KEY (another_table_key),
  ONSTRAINT another_table_reference_fk FOREIGN KEY (do_stuff_key)
      REFERENCES reference_table (reference_table_key) MATCH SIMPLE
      ON UPDATE NO ACTION ON DELETE SET NULL
);

--there are 50-60 tables which have similar foreign key references to reference_table

other_table と another_table の主キーを教えてくれるクエリを書きたいと思います。

擬似コード:

SELECT table_name, table_primary_key, table_fk_column_name
FROM ?????? some PG table ???????, reference_table
WHERE reference_table.reference_value IS NULL;

結果は次のようになります。

table_name | table_primary_key | table_fk_column_name | reference_table_pk
---------------------------------------------------------------------------
other_table   | 2                |  reference_table_key | 7
other_table   | 4                |  reference_table_key | 56
other_table   | 45               |  reference_table_key | 454
other_table   | 65765            |  reference_table_key | 987987
other_table   | 11               |  reference_table_key | 3213
another_table | 3                |  do_stuff_key        | 4645
another_table | 5                |  do_stuff_key        | 43546
another_table | 7                |  do_stuff_key        | 464356
unknown_table | 1                |  unkown_column_key   | 435435
unknown_table | 1                |  some_other_column_key | 34543
unknown_table | 3                |  unkown_column_key   | 124
unknown_table | 3                |  some_other_column_key | 123

これはPostgres: SQL to list table foreign keysと似ていますが、重複していません。その質問は、テーブル構造を示しています。特定のインスタンスを見つけたい。

基本的に私がそうであった場合、postgresは行2をNULLDELETE FROM reference_table WHERE reference_value IS NULL;に設定する必要があることを理解するために内部的に何かをしなければなりません。それらの行がどうなるか見たいです。reference_table_keyother_table

これを行うことができるクエリはありますか?その DELETE によってどのテーブル/行/列が影響を受けるかを教えてくれる DELETE 呼び出しに渡すことができる修飾子はありますか?

4

2 に答える 2

7

参照列の NULL 値

このクエリは、すべてのテーブルのすべての行を検索する DML ステートメントを生成します。ここで、列には別のテーブルを参照する外部キー制約がありますがNULL、その列に値が保持されます。

WITH x AS (
 SELECT c.conrelid::regclass    AS tbl
      , c.confrelid::regclass   AS ftbl
      , quote_ident(k.attname)  AS fk
      , quote_ident(pf.attname) AS pk
 FROM   pg_constraint c
 JOIN   pg_attribute  k ON (k.attrelid, k.attnum) = (c.conrelid, c.conkey[1])
 JOIN   pg_attribute  f ON (f.attrelid, f.attnum) = (c.confrelid, c.confkey[1])
 LEFT   JOIN pg_constraint p  ON p.conrelid = c.conrelid AND p.contype = 'p'
 LEFT   JOIN pg_attribute  pf ON (pf.attrelid, pf.attnum)
                               = (p.conrelid, p.conkey[1])
 WHERE  c.contype   = 'f'
 AND    c.confrelid = 'fk_tbl'::regclass  -- references to this tbl
 AND    f.attname   = 'fk_tbl_id'         -- and only to this column
)
SELECT string_agg(format(
'SELECT %L AS tbl
     , %L AS pk
     , %s::text AS pk_val
     , %L AS fk
     , %L AS ftbl
FROM   %1$s WHERE %4$s IS NULL'
                  , tbl
                  , COALESCE(pk 'NONE')
                  , COALESCE(pk 'NULL')
                  , fk
                  , ftbl), '
UNION ALL
') || ';'
FROM   x;

次のようなクエリを生成します。

SELECT 'some_tbl' AS tbl
     , 'some_tbl_id' AS pk
     , some_tbl_id::text AS pk_val
     , 'fk_tbl_id' AS fk
     , 'fk_tbl' AS ftbl
FROM   some_tbl WHERE fk_tbl_id IS NULL
UNION ALL
SELECT 'other_tbl' AS tbl
     , 'other_tbl_id' AS pk
     , other_tbl_id::text AS pk_val
     , 'some_name_id' AS fk
     , 'fk_tbl' AS ftbl
FROM   other_tbl WHERE some_name_id IS NULL;

次のような出力が生成されます。

    tbl    |     pk       | pk_val |    fk        |  ftbl
-----------+--------------+--------+--------------+--------
 some_tbl  | some_tbl_id  | 49     | fk_tbl_id    | fk_tbl
 some_tbl  | some_tbl_id  | 58     | fk_tbl_id    | fk_tbl
 other_tbl | other_tbl_id | 66     | some_name_id | fk_tbl
 other_tbl | other_tbl_id | 67     | some_name_id | fk_tbl
  • 複数列の外部キーまたは主キーを確実にカバーしません。これには、クエリをより複雑にする必要があります。

  • すべてのタイプをカバーするために、すべての主キーをにキャストします。text

  • これらの行を調整または削除して、他の列または任意の列/テーブルを指す外部キーを見つけます。

    AND    c.confrelid = 'fk_tbl'::regclass
    AND    f.attname = 'fk_tbl_id' -- and only this column
    
  • PostgreSQL 9.1.4 でテスト済み。私はpg_catalogテーブルを使用します。ここで使用するものは現実的に変更されることはありませんが、メジャー リリース間でそれが保証されるわけではありません。information_schema更新間で確実に動作する必要がある場合は、からのテーブルで書き直してください。それは遅くなりますが、確かです。

  • quote_ident()スキーマ修飾名では失敗するため、生成された DML スクリプトでテーブル名をサニタイズしませんでした。のような有害なテーブル名を避けるのはあなたの責任"users; DELETE * FROM users;"です。もう少し努力すれば、スキーマ名とテーブル名を別々に取得して を使用できますquote_ident()


参照列の NULL 値

私の最初の解決策は、あなたが説明したもの(私が理解しているように)が存在しないため、あなたが尋ねるものとは微妙に異なることを行います。値NULLは「不明」であり、参照できません。NULLFK制約がそれを指している列値を持つ行を実際に見つけたい場合(もちろん、値を持つ特定の行ではありませんNULL)、クエリははるかに単純化できます。

WITH x AS (
 SELECT c.confrelid::regclass   AS ftbl
       ,quote_ident(f.attname)  AS fk
       ,quote_ident(pf.attname) AS pk
       ,string_agg(c.conrelid::regclass::text, ', ') AS referencing_tbls
 FROM   pg_constraint c
 JOIN   pg_attribute  f ON (f.attrelid, f.attnum) = (c.confrelid, c.confkey[1])
 LEFT   JOIN pg_constraint p  ON p.conrelid = c.confrelid AND p.contype = 'p'
 LEFT   JOIN pg_attribute  pf ON (pf.attrelid, pf.attnum)
                               = (p.conrelid, p.conkey[1])
 WHERE  c.contype = 'f'
 -- AND    c.confrelid = 'fk_tbl'::regclass  -- only referring this tbl
 GROUP  BY 1, 2, 3
)
SELECT string_agg(format(
'SELECT %L AS ftbl
     , %L AS pk
     , %s::text AS pk_val
     , %L AS fk
     , %L AS referencing_tbls
FROM   %1$s WHERE %4$s IS NULL'
                  , ftbl
                  , COALESCE(pk, 'NONE')
                  , COALESCE(pk, 'NULL')
                  , fk
                  , referencing_tbls), '
UNION ALL
') || ';'
FROM   x;

データベース全体でそのような行をすべて検索します (1 つのテーブルへの制限をコメントアウトします)。Postgres 9.1.4 でテスト済みで、私にとってはうまくいきます。

同じ外部列を参照する複数のテーブルを 1 つのクエリにグループ化し、参照テーブルのリストを追加して概要を示します。

于 2012-08-03T03:29:34.583 に答える
0

このクエリの和集合が必要です。

select *
from ((select 'other_table' as table_name,
               other_table_key as primary_key,
               'reference_table_key' as table_fk,
               ot.reference_table_key
       from other_table ot left outer join
            reference_table rt
            on ot.reference_table_key = rt.reference_table_key
       where rt.reference_value is null
      ) union all
      (select 'another_table' as table_name,
               another_table_key as primary_key,
               'do_stuff_key' as table_fk,
               at.do_stuff_key
       from another_table at left outer join
            reference_table rt
            on at.do_stuff_key = rt.reference_table_key
       where rt.reference_value is null
      )
     ) t
于 2012-08-02T18:53:42.100 に答える