简体   繁体   English

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

[英]How can I find tables which reference a particular row via a foreign key?

Given a structure like this: 给定这样的结构:

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

I want to write a query that tells me the primary keys in other_table and another_table and potentially more tables where reference_value is NULL. 我想编写一个查询,告诉我other_table和another_table中的主键以及reference_value为NULL的更多表。

In psuedo-code: 在伪代码中:

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

The result would look something like: 结果如下所示:

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

This is similar to, but not a duplicate of Postgres: SQL to list table foreign keys . 这类似于但不是Postgres的重复:SQL列出表外键 That question shows the table structure. 这个问题说明了表的结构。 I want to find specific instances. 我想找到特定的实例。

Essentially if I were to DELETE FROM reference_table WHERE reference_value IS NULL; 本质上,如果我DELETE FROM reference_table WHERE reference_value IS NULL; , postgres has to do something internally to figure out that it needs to set reference_table_key in row 2 in other_table to NULL. ,Postgres的有做一些内部找出它需要一套reference_table_key在第2行中other_table为NULL。 I want to see what those rows would be. 我想看看这些行是什么。

Is there a query that can do this? 有查询可以做到这一点吗? Is there a modifier that I can pass to a DELETE call that would tell me what tables/rows/columns would be affected by that DELETE? 有没有可以传递给DELETE调用的修饰符,可以告诉我该DELETE将影响哪些表/行/列?

NULL values in referencing columns 引用列中的NULL值

This query produces the DML statement to find all rows in all tables, where a column has a foreign-key constraint referencing another table but hold a NULL value in that column: 此查询生成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;

Produces a query like this: 产生这样的查询:

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;

Produces output like this: 产生如下输出:

    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
  • Does not cover multi-column foreign or primary keys reliably . 不能可靠地覆盖多列外键或主键 You have to make the query more complex for this. 您必须为此使查询更复杂。

  • I cast all primary key values to text to cover all types. 我投所有的主键值 text涵盖所有类型。

  • Adapt or remove these lines to find foreign key pointing to an other or any column / table: 调整或删除这些行,以找到指向另一个或任何列/表的外键:

     AND c.confrelid = 'fk_tbl'::regclass AND f.attname = 'fk_tbl_id' -- and only this column 
  • Tested with PostgreSQL 9.1.4. 已在PostgreSQL 9.1.4中测试。 I use the pg_catalog tables. 我使用pg_catalog表。 Realistically nothing of what I use here is going to change, but that is not guaranteed across major releases. 实际上,我在这里使用的所有内容都不会改变,但这在主要版本中不能保证。 Rewrite it with tables from information_schema if you need it to work reliably across updates. 如果您需要它在更新中可靠地工作,请使用information_schema表重写它。 That is slower, but sure. 那比较慢,但是可以肯定。

  • I did not sanitize table names in the generated DML script, because quote_ident() would fail with schema-qualified names. 我没有在生成的DML脚本中quote_ident()表名,因为quote_ident()会因架构限定名而失败。 It is your responsibility to avoid harmful table names like "users; DELETE * FROM users;" 您有责任避免使用有害的表名,例如"users; DELETE * FROM users;" . With some more effort, you can retrieve schema-name and table name separately and use quote_ident() . 花费更多的精力,您可以分别检索架构名称和表名称,并使用quote_ident()


NULL values in referenced columns 引用列中的NULL值

My first solution does something subtly different from what you ask, because what you describe (as I understand it) is non-existent. 我的第一个解决方案与您的要求有一些细微的差别,因为您所描述的(根据我的理解)不存在。 The value NULL is "unknown" and cannot be referenced. NULL为“未知”,无法引用。 If you actually want to find rows with a NULL value in a column that has FK constraints pointing to it (not to the particular row with the NULL value, of course), then the query can be much simplified: 如果你真的想找到一个行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;

Finds all such rows in the entire database (commented out the restriction to one table). 在整个数据库中查找所有此类行(注释了对一个表的限制)。 Tested with Postgres 9.1.4 and works for me. 经过Postgres 9.1.4测试并为我工作。

I group multiple tables referencing the same foreign column into one query and add a list of referencing tables to give an overview. 我将多个引用同一外来列的表分组到一个查询中,并添加了一个引用表列表以进行概述。

You want a union for this query: 您需要此查询的联合:

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

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 在Oracle SQL中,如何找到哪些表引用了特定的列(即将其作为外键)? - In Oracle SQL , how can I find which tables reference a specific column (i.e have it as foreign key )? 如何查找具有外键行且列等于某物的行 - How can I find rows which have a foreign key row with column equal to something 如何在 sql 服务器中找到所有包含给定表主键外键的表? - How do I find all the tables which contains foreign key for given table primary key in sql server? 如何插入通过外键引用另一个 postgres 表的行,并在它不存在时创建外行? - How can I insert a row that references another postgres table via foreign key, and creates the foreign row too if it doesn't exist? 具有外键的表可以引用不同的表 - Table with foreign key that can reference different tables 如何使用自引用外键从表中删除行 - How can I Delete row from table with self reference foreign key 如何将具有相同外键的多个行的数据汇总到一行? - How can I sum data from mulitple rows which have the same foreign key into one row? 创建带有字段(带有外键)的表,该字段可以引用许多表并保持引用完整性? - Creating a table with a field (with a foreign key) which can reference many tables and maintain referencial integrity? 如何找出哪个表使用了特定的外键值? - How can I find out which table uses a specific foreign key value? 如何从特定表中查找特定行? - How can I find a particular row from a particular table?
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM