sql >> Database >  >> RDS >> PostgreSQL

Hoe kan ik tabellen vinden die via een externe sleutel naar een bepaalde rij verwijzen?

NULL-waarden in verwijzende kolommen

Deze query produceert de DML-instructie om alle rijen te vinden in alle tabellen, waar een kolom een ​​externe-sleutelbeperking heeft verwijzend naar een andere tabel maar houd een NULL . vast waarde in die kolom:

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;

Produceert een zoekopdracht als deze:

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;

Produceert output als volgt:

    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
  • Dekt niet op betrouwbare wijze buitenlandse of primaire sleutels met meerdere kolommen . Hiervoor moet je de query ingewikkelder maken.

  • Ik cast alle primaire sleutel waarden naar text om alle soorten te dekken.

  • Pas deze regels aan of verwijder ze om een ​​refererende sleutel te vinden die naar een andere of een wijst kolom / tabel:

    AND    c.confrelid = 'fk_tbl'::regclass
    AND    f.attname = 'fk_tbl_id' -- and only this column
    
  • Getest met PostgreSQL 9.1.4. Ik gebruik de pg_catalog tafels. Realistisch gezien zal er niets veranderen van wat ik hier gebruik, maar dat is niet gegarandeerd bij grote releases. Herschrijf het met tabellen uit information_schema als u het nodig hebt om betrouwbaar te werken tussen updates. Dat is langzamer, maar zeker.

  • Ik heb de tabelnamen in het gegenereerde DML-script niet opgeschoond, omdat quote_ident() zou mislukken met schema-gekwalificeerde namen. Het is uw verantwoordelijkheid om schadelijke tabelnamen zoals "users; DELETE * FROM users;" te vermijden . Met wat meer moeite kunt u schemanaam en tabelnaam afzonderlijk ophalen en quote_ident() gebruiken .

NULL-waarden in kolommen waarnaar wordt verwezen

Mijn eerste oplossing doet iets subtiel anders dan wat je vraagt, omdat wat je beschrijft (zoals ik het begrijp) niet bestaat. De waarde NULL is "onbekend" en er kan niet naar worden verwezen. Als u rijen wilt vinden met een NULL waarde in een kolom met FK-beperkingen die naar . verwijzen het (niet naar de specifieke rij met de NULL waarde natuurlijk), dan kan de vraag veel vereenvoudigd worden:

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;

Vindt al dergelijke rijen in de hele database (commentaar op de beperking tot één tabel). Getest met Postgres 9.1.4 en werkt voor mij.

Ik groepeer meerdere tabellen die verwijzen naar dezelfde buitenlandse kolom in één zoekopdracht en voeg een lijst met referentietabellen toe om een ​​overzicht te geven.



  1. Datum tussen 2 andere data, jaartal buiten beschouwing gelaten

  2. Hoe Odoo 12 te clusteren met PostgreSQL-streamingreplicatie voor hoge beschikbaarheid

  3. Wat is een goede benadering voor het beheren van de db-verbinding in een Google Cloud SQL (GAE) Python-app?

  4. Wacht op meerdere db-verbindingen voordat u de express-server start?