sql >> データベース >  >> RDS >> PostgreSQL

外部キーを介して特定の行を参照するテーブルを見つけるにはどうすればよいですか?

    参照列の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
      
    • PostgreSQL9.1.4でテスト済み。 pg_catalogを使用しています テーブル。現実的には、ここで使用するものは何も変更されませんが、メジャーリリース間で保証されるわけではありません。 information_schemaのテーブルで書き直します 更新間で確実に機能する必要がある場合。それは遅いですが、確かです。

    • quote_ident() スキーマ修飾名では失敗します。 "users; DELETE * FROM users;"のような有害なテーブル名を避けるのはあなたの責任です。 。もう少し努力すれば、スキーマ名とテーブル名を別々に取得して、quote_ident()を使用できます。 。

    参照される列のNULL値

    私の最初の解決策は、あなたが説明するもの(私が理解しているように)が存在しないため、あなたが尋ねるものとは微妙に異なることをします。値NULL は「不明」であり、参照できません。実際にNULLの行を検索する場合 を指すを指すFK制約がある列の値 それ(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つのクエリにグループ化し、参照テーブルのリストを追加して概要を示します。



    1. MySQL5.7でネストされたJSONデータ型を更新する方法

    2. mysqlで最も古い日時値を取得します

    3. 複数の.sqlダンプファイルをシェルからmysqlデータベースにインポートします

    4. SQLでJSONオブジェクトの配列として返す(Postgres)