PostgreSQL
 sql >> база данни >  >> RDS >> PostgreSQL

Как мога да намеря таблици, които препращат към определен ред чрез външен ключ?

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 и работи за мен.

Групирам множество таблици, препращащи към една и съща чужда колона, в една заявка и добавям списък от препращащи таблици, за да дам общ преглед.



  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. PostgreSQL:Какъв е максималният брой таблици, които могат да се съхраняват в базата данни на postgreSQL?

  2. Как мога (или мога) да ИЗБЕРЯ DISTINCT на няколко колони?

  3. Възможно ли е да замените Cloud SQL прокси с Istio прокси?

  4. Да се ​​използва ли имейл адресът като основен ключ?

  5. Как да се свържете в мрежа между Docker изображения по време на изграждане?