如何找到通过外键引用特定行的表?

时间:2012-08-02 18:34:15

标签: sql postgresql foreign-keys

给出这样的结构:

CREATE TABLE reference_table (
  reference_table_key numeric NOT NULL,
  reference_value numeric,
  CONSTRAINT reference_table_pk PRIMARY KEY (reference_table_key)
);

CREATE TABLE other_table (
  other_table_key numeric NOT NULL,
  reference_table_key numeric,
  CONSTRAINT other_table_pk PRIMARY KEY (other_table_key),
  ONSTRAINT other_table_reference_fk FOREIGN KEY (reference_table_key)
      REFERENCES reference_table (reference_table_key) MATCH SIMPLE
      ON UPDATE NO ACTION ON DELETE SET NULL
);

CREATE TABLE another_table (
  another_table_key numeric NOT NULL,
  do_stuff_key numeric,
  CONSTRAINT another_table_pk PRIMARY KEY (another_table_key),
  ONSTRAINT another_table_reference_fk FOREIGN KEY (do_stuff_key)
      REFERENCES reference_table (reference_table_key) MATCH SIMPLE
      ON UPDATE NO ACTION ON DELETE SET NULL
);

--there are 50-60 tables which have similar foreign key references to reference_table

我想编写一个查询,告诉我other_table和another_table中的主键以及reference_value为NULL的更多表。

在伪代码中:

SELECT table_name, table_primary_key, table_fk_column_name
FROM ?????? some PG table ???????, reference_table
WHERE reference_table.reference_value IS NULL;

结果看起来像是:

table_name | table_primary_key | table_fk_column_name | reference_table_pk
---------------------------------------------------------------------------
other_table   | 2                |  reference_table_key | 7
other_table   | 4                |  reference_table_key | 56
other_table   | 45               |  reference_table_key | 454
other_table   | 65765            |  reference_table_key | 987987
other_table   | 11               |  reference_table_key | 3213
another_table | 3                |  do_stuff_key        | 4645
another_table | 5                |  do_stuff_key        | 43546
another_table | 7                |  do_stuff_key        | 464356
unknown_table | 1                |  unkown_column_key   | 435435
unknown_table | 1                |  some_other_column_key | 34543
unknown_table | 3                |  unkown_column_key   | 124
unknown_table | 3                |  some_other_column_key | 123

这与Postgres: SQL to list table foreign keys类似,但不重复。那个问题显示了表结构。我想找到具体的实例。

基本上如果我去DELETE FROM reference_table WHERE reference_value IS NULL;,postgres必须在内部做一些事情,以确定它需要将reference_table_key中第2行中的other_table设置为NULL。我想知道那些行是什么。

是否有可以执行此操作的查询?是否有一个修饰符可以传递给DELETE调用,该调用将告诉我DELETE会影响哪些表/行/列?

2 个答案:

答案 0 :(得分:5)

引用列

中的NULL值

此查询生成DML语句以在所有表​​中查找所有行,其中列具有外键约束引用另一个表但保留{{1}该列中的值:

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
  • 使用PostgreSQL 9.1.4进行测试。我使用AND c.confrelid = 'fk_tbl'::regclass AND f.attname = 'fk_tbl_id' -- and only this column 表。实际上,我在这里使用的内容没有任何改变,但在主要版本中无法保证。如果需要它可以在更新中可靠地工作,请使用pg_catalog中的表重写它。这比较慢,但确定。

  • 我没有在生成的DML脚本中清理表名,因为quote_ident()会因模式限定名而失败。您有责任避免使用有害的表名,例如information_schema。通过更多努力,您可以单独检索模式名称和表名,并使用"users; DELETE * FROM users;"


引用列中的NULL值

我的第一个解决方案与你提出的问题略有不同,因为你描述的内容(据我所知)并不存在。值quote_ident()是“未知”,无法引用。如果您确实希望在列中具有NULL值的行中具有指向的FK约束(当然不是具有NULL值的特定行) ,那么查询可以大大简化:

NULL

查找整个数据库中的所有这些行(将限制注释到一个表)。使用Postgres 9.1.4测试并为我工作。

我将引用同一外部列的多个表分组到一个查询中,并添加一个引用表列表以提供概述。

答案 1 :(得分:0)

您需要此查询的联合:​​

select *
from ((select 'other_table' as table_name,
               other_table_key as primary_key,
               'reference_table_key' as table_fk,
               ot.reference_table_key
       from other_table ot left outer join
            reference_table rt
            on ot.reference_table_key = rt.reference_table_key
       where rt.reference_value is null
      ) union all
      (select 'another_table' as table_name,
               another_table_key as primary_key,
               'do_stuff_key' as table_fk,
               at.do_stuff_key
       from another_table at left outer join
            reference_table rt
            on at.do_stuff_key = rt.reference_table_key
       where rt.reference_value is null
      )
     ) t
相关问题