NULL-värden i refererande kolumner
Den här frågan producerar DML-satsen för att hitta alla rader i alla tabeller, där en kolumn har en begränsning med främmande nyckel som refererar till en annan tabell men håll en NULL
värde i den kolumnen:
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;
Ger en fråga som denna:
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;
Ger utdata så här:
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
-
Täcker inte främmande eller primärnycklar med flera kolumner på ett tillförlitligt sätt . Du måste göra frågan mer komplex för detta.
-
Jag castar alla primära nyckel-värden till
text
för att täcka alla typer. -
Anpassa eller ta bort dessa rader för att hitta främmande nyckel som pekar på en annan eller vilken som helst kolumn/tabell:
AND c.confrelid = 'fk_tbl'::regclass AND f.attname = 'fk_tbl_id' -- and only this column
-
Testad med PostgreSQL 9.1.4. Jag använder
pg_catalog
tabeller. Realistiskt sett kommer ingenting av det jag använder här att förändras, men det är inte garanterat över större utgåvor. Skriv om det med tabeller fråninformation_schema
om du behöver det för att fungera tillförlitligt över uppdateringar. Det är långsammare, men säkert. -
Jag sanerade inte tabellnamn i det genererade DML-skriptet eftersom
quote_ident()
skulle misslyckas med schemakvalificerade namn. Det är ditt ansvar att undvika skadliga tabellnamn som"users; DELETE * FROM users;"
. Med lite mer ansträngning kan du hämta schemanamn och tabellnamn separat och användaquote_ident()
.
NULL-värden i refererade kolumner
Min första lösning gör något subtilt annorlunda än vad du frågar om, eftersom det du beskriver (som jag förstår det) är obefintligt. Värdet NULL
är "okänt" och kan inte refereras. Om du verkligen vill hitta rader med en NULL
värde i en kolumn som har FK-begränsningar som pekar till den (inte till den specifika raden med NULL
värde, naturligtvis), då kan frågan förenklas mycket:
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;
Hittar alla sådana rader i hela databasen (kommenterade ut begränsningen till en tabell). Testat med Postgres 9.1.4 och fungerar för mig.
Jag grupperar flera tabeller som refererar till samma främmande kolumn i en fråga och lägger till en lista med referenstabeller för att ge en översikt.