参照列の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つのクエリにグループ化し、参照テーブルのリストを追加して概要を示します。