PostgreSql:获取(通过外键)引用表中特定行的所有行

问题描述 投票:10回答:3

这似乎很简单,但是我无法找到这个问题的答案。

我想要什么?具有行的主表会在不再引用(通过外键)时删除自己。解决方案可能特定于PostgreSql,也可能不特定于此。

How?解决此问题的一种方法(实际上,到目前为止,唯一的方法)涉及以下内容:对于引用该主表的每个表,在行UPDATEDELETE上,要检查主数据库中的引用行,还有多少其他行仍引用该引用行。如果它降到零,那么我也要删除master中的该行。

((如果您有更好的主意,我想知道!)

详细:我有一个主表被许多其他人引用

CREATE TABLE master (
  id serial primary key,
  name text unique not null
);

其他所有表通常具有相同的格式:

CREATE TABLE other (
  ...
  master_id integer references master (id)
  ...
);

如果其中一个不是NULL,则它们引用master中的一行。如果我尝试删除它,则会收到一条错误消息,因为它已经被引用:

ERROR:  update or delete on table "master" violates foreign key constraint "other_master_id_fkey" on table "other"
DETAIL:  Key (id)=(1) is still referenced from table "other".
Time: 42.972 ms

请注意,即使我有很多引用master的表,也无需花太多时间就可以弄清楚。我如何找到这些信息而不必引发错误?

sql database postgresql
3个回答
4
投票

您可以执行以下任一操作:

1)将reference_count字段添加到主表。每当添加带有reference count的行时,在明细表上使用触发器都会增加master_id。当删除行时减少计数。 reference_count达到0时-删除记录。

2)使用pg_constraint表(详细信息here)获取引用表的列表并创建动态SQL查询。

3)在每个明细表上创建触发器,从而删除主表中的master_id。使用BEGIN ... EXCEPTION ... END沉默错误消息。


0
投票
SELECT * 
FROM master ma
WHERE EXISTS (
    SELECT *
    FROM other ot
    WHERE ot.master_id = ma.id
    );

或者相反:

SELECT * 
FROM other ot
WHERE EXISTS (
    SELECT *    
    FROM master ma
    WHERE ot.master_id = ma.id
    );

因此,如果您只想更新(或删除)master中未被other引用的行,则可以:

UPDATE master ma
SET id = 1000+id
  , name = 'blue'
WHERE name = 'green'
AND NOT EXISTS (
    SELECT *
    FROM other ot
    WHERE ot.master_id = ma.id
    );

0
投票

如果有人想要引用引用给定主行的所有其他表中的行的真实计数,则这里是一些PL / pgSQL。请注意,这在单列约束的普通情况下有效。它涉及多列约束。

CREATE OR REPLACE FUNCTION count_references(master regclass, pkey_value integer,
    OUT "table" regclass, OUT count integer)
    RETURNS SETOF record 
    LANGUAGE 'plpgsql'
    VOLATILE 
AS $BODY$
declare
  x record;           -- constraint info for each table in question that references master
  sql text;           -- temporary buffer
begin
  for x in
    select conrelid, attname
    from pg_constraint
    join pg_attribute on conrelid=attrelid and attnum=conkey[1]
    where contype='f' and confrelid=master
      and confkey=( -- here we assume that FK references master's PK
        select conkey
        from pg_constraint
        where conrelid=master and contype='p'
      )
  loop
        "table" = x.conrelid;
    sql = format('select count(*) from %s where %I=$1', "table", x.attname);
    execute sql into "count" using pkey_value;
    return next;
  end loop;
end
$BODY$;

然后像这样使用它

select * from count_references('master', 1) where count>0

这将返回表列表,这些表具有对ID = 1的主表的引用。

© www.soinside.com 2019 - 2024. All rights reserved.