Hodnoty NULL v odkazujících sloupcích
Tento dotaz vytvoří příkaz DML k nalezení všech řádků ve všech tabulkách, kde sloupec má omezení cizího klíče odkazující na jinou tabulku ale podržte NULL
hodnota v tomto sloupci:
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;
Vytvoří dotaz, jako je tento:
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;
Produkuje výstup takto:
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
-
Nepokrývá spolehlivě cizí nebo primární klíče s více sloupci . K tomu musíte udělat dotaz složitější.
-
Odesílám všechny hodnoty primárního klíče na
text
pokrývat všechny typy. -
Upravte nebo odstraňte tyto řádky, abyste našli cizí klíč směřující na jiný nebo jakýkoli sloupec / tabulka:
AND c.confrelid = 'fk_tbl'::regclass AND f.attname = 'fk_tbl_id' -- and only this column
-
Testováno s PostgreSQL 9.1.4. Používám
pg_catalog
tabulky. Realisticky se nic z toho, co zde používám, nezmění, ale to není zaručeno u hlavních vydání. Přepište jej pomocí tabulek zinformation_schema
pokud potřebujete, aby fungovala spolehlivě napříč aktualizacemi. Je to pomalejší, ale jistě. -
Nedezinfikoval jsem názvy tabulek ve vygenerovaném skriptu DML, protože
quote_ident()
selže s názvy kvalifikovanými pro schéma. Je vaší odpovědností vyhnout se škodlivým názvům tabulek jako"users; DELETE * FROM users;"
. S trochou většího úsilí můžete načíst název schématu a název tabulky samostatně a použítquote_ident()
.
Hodnoty NULL v odkazovaných sloupcích
Moje první řešení dělá něco jemně odlišného od toho, na co se ptáte, protože to, co popisujete (jak tomu rozumím), neexistuje. Hodnota NULL
je "neznámý" a nelze na něj odkazovat. Pokud skutečně chcete najít řádky s NULL
hodnotu ve sloupci, který má omezení FK směřující na to (ne na konkrétní řádek s NULL
hodnota, samozřejmě), pak lze dotaz značně zjednodušit:
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;
Najde všechny takové řádky v celé databázi (komentováno omezení na jednu tabulku). Testováno s Postgres 9.1.4 a funguje pro mě.
Seskupuji více tabulek odkazujících na stejný cizí sloupec do jednoho dotazu a přidávám seznam odkazujících tabulek, abych poskytl přehled.