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
-
Тествано с PostgreSQL 9.1.4. Използвам
pg_catalog
маси. Реално погледнато, нищо от това, което използвам тук, няма да се промени, но това не е гарантирано за основните версии. Пренапишете го с таблици отinformation_schema
ако имате нужда от него, за да работи надеждно при актуализации. Това е по-бавно, но сигурно. -
Не дезинфекцирах имената на таблици в генерирания DML скрипт, защото
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;
Намира всички такива редове в цялата база данни (коментирано ограничението до една таблица). Тестван с Postgres 9.1.4 и работи за мен.
Групирам множество таблици, препращащи към една и съща чужда колона, в една заявка и добавям списък от препращащи таблици, за да дам общ преглед.