sql >> Database teknologi >  >> RDS >> PostgreSQL

Hvordan kan jeg finde tabeller, der refererer til en bestemt række via en fremmednøgle?

NULL-værdier i refererende kolonner

Denne forespørgsel producerer DML-sætningen for at finde alle rækker i alle tabeller, hvor en kolonne har en fremmednøglebegrænsning der henviser til en anden tabel men hold en NULL værdi i den kolonne:

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;
 

Frembringer en forespørgsel som denne:

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;
 

Producerer output som dette:

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
  • Dækker ikke udenlandske eller primære nøgler med flere kolonner på en pålidelig måde . Du skal gøre forespørgslen mere kompleks for dette.

  • Jeg caster alle primære nøgle værdier til text til at dække alle typer.

  • Tilpas eller fjern disse linjer for at finde fremmednøgle, der peger på en anden eller enhver kolonne / tabel:

    AND    c.confrelid = 'fk_tbl'::regclass
    AND    f.attname = 'fk_tbl_id' -- and only this column
     
  • Testet med PostgreSQL 9.1.4. Jeg bruger pg_catalog borde. Realistisk set vil intet af det, jeg bruger her, ændre sig, men det er ikke garanteret på tværs af større udgivelser. Omskriv det med tabeller fra information_schema hvis du har brug for det til at fungere pålideligt på tværs af opdateringer. Det er langsommere, men sikkert.

  • Jeg rensede ikke tabelnavne i det genererede DML-script, fordi quote_ident() ville mislykkes med skema-kvalificerede navne. Det er dit ansvar at undgå skadelige tabelnavne som "users; DELETE * FROM users;" . Med lidt mere indsats kan du hente skemanavn og tabelnavn separat og bruge quote_ident() .

NULL-værdier i refererede kolonner

Min første løsning gør noget subtilt anderledes end det du spørger om, for det du beskriver (som jeg forstår det) er ikke-eksisterende. Værdien NULL er "ukendt" og kan ikke refereres. Hvis du rent faktisk ønsker at finde rækker med en NULL værdi i en kolonne, der har FK-begrænsninger, der peger til det (ikke til den bestemte række med NULL værdi, selvfølgelig), så kan forespørgslen være meget forenklet:

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;
 

Finder alle sådanne rækker i hele databasen (kommenterede begrænsningen til én tabel). Testet med Postgres 9.1.4 og virker for mig.

Jeg grupperer flere tabeller, der refererer til den samme fremmede kolonne, i én forespørgsel og tilføjer en liste over referencetabeller for at give et overblik.



  1. Inkrementel datareplikering i IRI Workbench

  2. Ingen resultater returneret af forespørgselsfejlen i PostgreSQL

  3. Brug af JavaFX-tabeller til at organisere data

  4. Beregn en løbende total i MySQL