Nilai NULL dalam kolom referensi
Kueri ini menghasilkan pernyataan DML untuk menemukan semua baris di semua tabel, di mana kolom memiliki batasan kunci asing mereferensikan tabel lain tapi tahan NULL
nilai di kolom itu:
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;
Menghasilkan kueri seperti ini:
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;
Menghasilkan output seperti ini:
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
-
Tidak mencakup kunci asing atau kunci utama multi-kolom dengan andal . Anda harus membuat kueri lebih kompleks untuk ini.
-
Saya memberikan semua nilai kunci utama ke
text
untuk mencakup semua jenis. -
Sesuaikan atau hapus baris ini untuk menemukan kunci asing yang menunjuk ke yang lain atau apa saja kolom/tabel:
AND c.confrelid = 'fk_tbl'::regclass AND f.attname = 'fk_tbl_id' -- and only this column
-
Diuji dengan PostgreSQL 9.1.4. Saya menggunakan
pg_catalog
tabel. Secara realistis, apa yang saya gunakan di sini tidak akan berubah, tetapi itu tidak dijamin di seluruh rilis utama. Tulis ulang dengan tabel dariinformation_schema
jika Anda membutuhkannya untuk bekerja dengan andal di seluruh pembaruan. Itu lebih lambat, tapi pasti. -
Saya tidak membersihkan nama tabel dalam skrip DML yang dihasilkan, karena
quote_ident()
akan gagal dengan nama yang memenuhi syarat skema. Anda bertanggung jawab untuk menghindari nama tabel yang berbahaya seperti"users; DELETE * FROM users;"
. Dengan lebih banyak usaha, Anda dapat mengambil nama skema dan nama tabel secara terpisah dan menggunakanquote_ident()
.
Nilai NULL di kolom referensi
Solusi pertama saya melakukan sesuatu yang agak berbeda dari apa yang Anda minta, karena apa yang Anda gambarkan (seperti yang saya pahami) tidak ada. Nilai NULL
adalah "tidak diketahui" dan tidak dapat dirujuk. Jika Anda benar-benar ingin menemukan baris dengan NULL
nilai dalam kolom yang memiliki batasan FK yang menunjuk ke itu (bukan ke baris tertentu dengan NULL
nilai, tentu saja), maka kueri dapat lebih disederhanakan:
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;
Menemukan semua baris seperti itu di seluruh database (mengomentari batasan ke satu tabel). Diuji dengan Postgres 9.1.4 dan berfungsi untuk saya.
Saya mengelompokkan beberapa tabel yang mereferensikan kolom asing yang sama ke dalam satu kueri dan menambahkan daftar tabel referensi untuk memberikan gambaran umum.