PostgreSQL
 sql >> Teknologi Basis Data >  >> RDS >> PostgreSQL

Bagaimana saya bisa menemukan tabel yang mereferensikan baris tertentu melalui kunci asing?

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 dari information_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 menggunakan quote_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.



  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Cara menggunakan Joda-Time dengan java.sql.Timestamp

  2. Cara menemukan kemunculan pertama dan terakhir dari karakter tertentu di dalam string di PostgreSQL

  3. Heroku psql:FATAL:slot koneksi yang tersisa dicadangkan untuk koneksi superuser non-replikasi

  4. perhitungan persentil ke-n di postgresql

  5. Mendapatkan hasil antara dua tanggal di PostgreSQL