NULL-Werte in referenzierenden Spalten
Diese Abfrage erzeugt die DML-Anweisung, um alle Zeilen zu finden in allen Tabellen, in denen eine Spalte eine Fremdschlüsseleinschränkung auf eine andere Tabelle verweist hat aber halten Sie ein NULL
Wert in dieser Spalte:
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;
Erzeugt eine Abfrage wie diese:
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;
Erzeugt eine Ausgabe wie diese:
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
-
Überdeckt mehrspaltige Fremd- oder Primärschlüssel nicht zuverlässig . Dazu müssen Sie die Abfrage komplexer machen.
-
Ich caste alle Werte des Primärschlüssels zu
text
um alle Typen abzudecken. -
Passen Sie diese Zeilen an oder entfernen Sie sie, um Fremdschlüssel zu finden, die auf einen anderen oder beliebigen zeigen Spalte / Tabelle:
AND c.confrelid = 'fk_tbl'::regclass AND f.attname = 'fk_tbl_id' -- and only this column
-
Getestet mit PostgreSQL 9.1.4. Ich verwende den
pg_catalog
Tische. Realistischerweise wird sich nichts von dem, was ich hier verwende, ändern, aber das ist nicht für alle Hauptversionen garantiert. Schreiben Sie es mit Tabellen ausinformation_schema
um wenn Sie es brauchen, um über Updates hinweg zuverlässig zu funktionieren. Das ist langsamer, aber sicher. -
Ich habe Tabellennamen im generierten DML-Skript nicht bereinigt, weil
quote_ident()
würde mit Schema-qualifizierten Namen fehlschlagen. Es liegt in Ihrer Verantwortung, schädliche Tabellennamen wie"users; DELETE * FROM users;"
zu vermeiden . Mit etwas mehr Aufwand können Sie Schemaname und Tabellenname separat abrufen undquote_ident()
verwenden .
NULL-Werte in referenzierten Spalten
Meine erste Lösung unterscheidet sich subtil von dem, was Sie fragen, weil das, was Sie beschreiben (so wie ich es verstehe), nicht existiert. Der Wert NULL
ist "unbekannt" und kann nicht referenziert werden. Wenn Sie tatsächlich Zeilen mit einem NULL
finden möchten Wert in einer Spalte, die FK-Einschränkungen aufweist, die auf zeigen it (nicht auf die bestimmte Zeile mit dem NULL
Wert natürlich), dann kann die Abfrage stark vereinfacht werden:
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;
Findet alle solche Zeilen in der gesamten Datenbank (Auskommentierung der Beschränkung auf eine Tabelle). Getestet mit Postgres 9.1.4 und funktioniert bei mir.
Ich gruppiere mehrere Tabellen, die auf dieselbe Fremdspalte verweisen, in einer Abfrage und füge eine Liste der verweisenden Tabellen hinzu, um einen Überblick zu geben.