我如何 SELECT all (table, column) 引用相同的列作为外键
How do I SELECT all (table, column) referencing the same column as foreign key
(TL;最后是DR)
我正在合并 2 个大小合适的 postgres 数据库。
由于存在 ID 冲突和许多外键,我会喜欢 UPDATE foo SET bar_id = bar_id + 100000 CASCADE
是 SQL 中的一个东西,所以它神奇地相应地更新了所有内容。不幸的是,它不是。
所以我想使用一个 LOOP 结构(见下文),它将简单地编辑各处的引用。
我想要一个 select 查询 return 所有 table_name,column_name 引用我想要的列。
DO
$$
DECLARE
rec record;
BEGIN
FOR rec IN
(SELECT table_name, column_name FROM /*??*/ WHERE /*??*/) -- <<< This line
LOOP
EXECUTE format('UPDATE %I SET %s = %s + 100000 ;',
rec.table_name,rec.column_name,rec.column_name);
END LOOP;
END;
$$
LANGUAGE plpgsql;
我已经知道如何让所有 tables (+column_name) 具有我在外键列与其引用的列共享名称时使用的特定 column_name .或者即使它是 column_name 我知道的列表:
SELECT col.table_name, col.column_name
FROM information_schema.columns col
right join
information_schema.tables tab
ON col.table_name = tab.table_name
WHERE column_name = 'foo_id'
-- IN ('FOO_ID','BAR_FOO_ID') | or : like '%foo_id' | both works well most of the time
and tab.table_type = 'BASE TABLE'
但是……
我现在有一个 table PLACES,其中 place_id
列在至少 60 个不同的约束条件下被引用(匹配 LIKE '%place_id'
)。 然后是引用以其他方式命名的地点 ID 的列 ,例如 'foo_currentplace'、'foo_storageroom'、'foo_lastrecomposition_place'、'operating_theatre' 等。另一方面,有从 placetype table 引用 'placetype_id' 的列是 LIKE '%place%'
,我不想更改 placetype_id,所以我们无法猜测是哪一列包括或不仅包括他们的名字。
我知道有 information_schema.table_constraints
table,但它没有告诉引用的列。
如果我们可以从约束名称中获得定义,则可以匹配:
ILIKE format('%%REFERENCES %s(%s)%%',table_name,column_name)
但定义也不是 table_constraints
table 的一部分。
(对于那些想知道的人,我正在研究与绝育服务相关的医院数据库。)
我想要什么/TL;DR
我需要一个 SELECT 查询(或函数定义)returning 整个数据库的所有列 (schema_name,table_name,column_name)
或 (table_name,column_name)
具有引用一个外键约束指定的列(参数)。
评论可能太长了。
Postgres 绝对支持级联更新约束(参见 here)。但是,这是约束的 定义 的一部分,而不是 update
语句:
ALTER TABLE foo
ADD FOREIGN KEY fk_foo_bar_id FOREIGN KEY (bar_id) REFERENCES bar(bar_id)
ON UPDATE CASCADE;
----^ this is the important part
注意:您需要重新定义所有外键约束,使它们成为级联更新约束。
而且,作为编辑评论,我通常会避免级联更新外键约束(因为我不喜欢主键更改值的想法)。但是,这绝对是它们有用的地方。
然后,如果您更改 bar.bar_id
,更改将反映在 foo
中。 Here 是一个 db<>fiddle.
好的,我已经完成了:-)
以下查询 returns 数据库中的每一列引用 FOO_TABLE.foo_column
作为外键:
SELECT
fk.table_schema as schema, --optional in my case, I only use public
fk.table_name as table,
substring(fk.constraint_def, 14, position(')' in constraint_def)-14) as column
FROM
(SELECT tc.*,
pg_get_constraintdef(c.oid) as constraint_def
--,c.oid
from pg_constraint c
left join information_schema.table_constraints tc
on c.conname = tc.constraint_name
where tc.constraint_type = 'FOREIGN KEY')
as fk
WHERE constraint_def ILIKE format('%%REFERENCES %s(%s)%%',
'FOO_TABLE','foo_column')
ORDER BY table_schema,table_name,3;
我发现 information_schema.table_constraints
大部分信息来自 pg_constraint
,包括内部参考 OID
,并且有一个内置函数 pg_get_constraintdef()
返回从 OID
.
定义约束对象
然后,定义的一些子字符串足以提取 column_name
AND
使用我在问题中准备的 (I)LIKE
过滤器过滤引用的列。
---------------- 其他答案-----------------
我根据改进@Abelisto 建议构建的另一个可接受的查询:
SELECT table_name, column_name
FROM (SELECT table_name, SUBSTR(column_name, 2, LENGTH(column_name)-2) as column_name,
referenced_table,SUBSTR(referenced_column, 2, LENGTH(referenced_column)-2) as referenced_column
FROM(select
conrelid::regclass::text as table_name,
(select array_agg(attname) from pg_attribute where conrelid = attrelid and attnum = any(conkey))::text as column_name,
confrelid::regclass::text as referenced_table,
(select array_agg(attname) from pg_attribute where confrelid = attrelid and attnum = any(confkey))::text as referenced_column
from pg_constraint where contype = 'f'
) b ) a
WHERE (referenced_table, referenced_column) = 'FOO_TABLE','foo_column');
我认为表演在那里并不重要,所以应该根据副需求来选择。我认为我的第一个解决方案具有获得约束定义的优势,如果你想改变它(例如,添加一个 ON UPDATE CASCADE
子句),但第二个似乎更“紧凑”,只是为了返回table.column.
(TL;最后是DR)
我正在合并 2 个大小合适的 postgres 数据库。
由于存在 ID 冲突和许多外键,我会喜欢 UPDATE foo SET bar_id = bar_id + 100000 CASCADE
是 SQL 中的一个东西,所以它神奇地相应地更新了所有内容。不幸的是,它不是。
所以我想使用一个 LOOP 结构(见下文),它将简单地编辑各处的引用。 我想要一个 select 查询 return 所有 table_name,column_name 引用我想要的列。
DO
$$
DECLARE
rec record;
BEGIN
FOR rec IN
(SELECT table_name, column_name FROM /*??*/ WHERE /*??*/) -- <<< This line
LOOP
EXECUTE format('UPDATE %I SET %s = %s + 100000 ;',
rec.table_name,rec.column_name,rec.column_name);
END LOOP;
END;
$$
LANGUAGE plpgsql;
我已经知道如何让所有 tables (+column_name) 具有我在外键列与其引用的列共享名称时使用的特定 column_name .或者即使它是 column_name 我知道的列表:
SELECT col.table_name, col.column_name
FROM information_schema.columns col
right join
information_schema.tables tab
ON col.table_name = tab.table_name
WHERE column_name = 'foo_id'
-- IN ('FOO_ID','BAR_FOO_ID') | or : like '%foo_id' | both works well most of the time
and tab.table_type = 'BASE TABLE'
但是……
我现在有一个 table PLACES,其中 place_id
列在至少 60 个不同的约束条件下被引用(匹配 LIKE '%place_id'
)。 然后是引用以其他方式命名的地点 ID 的列 ,例如 'foo_currentplace'、'foo_storageroom'、'foo_lastrecomposition_place'、'operating_theatre' 等。另一方面,有从 placetype table 引用 'placetype_id' 的列是 LIKE '%place%'
,我不想更改 placetype_id,所以我们无法猜测是哪一列包括或不仅包括他们的名字。
我知道有 information_schema.table_constraints
table,但它没有告诉引用的列。
如果我们可以从约束名称中获得定义,则可以匹配:
ILIKE format('%%REFERENCES %s(%s)%%',table_name,column_name)
但定义也不是 table_constraints
table 的一部分。
(对于那些想知道的人,我正在研究与绝育服务相关的医院数据库。)
我想要什么/TL;DR
我需要一个 SELECT 查询(或函数定义)returning 整个数据库的所有列 (schema_name,table_name,column_name)
或 (table_name,column_name)
具有引用一个外键约束指定的列(参数)。
评论可能太长了。
Postgres 绝对支持级联更新约束(参见 here)。但是,这是约束的 定义 的一部分,而不是 update
语句:
ALTER TABLE foo
ADD FOREIGN KEY fk_foo_bar_id FOREIGN KEY (bar_id) REFERENCES bar(bar_id)
ON UPDATE CASCADE;
----^ this is the important part
注意:您需要重新定义所有外键约束,使它们成为级联更新约束。
而且,作为编辑评论,我通常会避免级联更新外键约束(因为我不喜欢主键更改值的想法)。但是,这绝对是它们有用的地方。
然后,如果您更改 bar.bar_id
,更改将反映在 foo
中。 Here 是一个 db<>fiddle.
好的,我已经完成了:-)
以下查询 returns 数据库中的每一列引用 FOO_TABLE.foo_column
作为外键:
SELECT
fk.table_schema as schema, --optional in my case, I only use public
fk.table_name as table,
substring(fk.constraint_def, 14, position(')' in constraint_def)-14) as column
FROM
(SELECT tc.*,
pg_get_constraintdef(c.oid) as constraint_def
--,c.oid
from pg_constraint c
left join information_schema.table_constraints tc
on c.conname = tc.constraint_name
where tc.constraint_type = 'FOREIGN KEY')
as fk
WHERE constraint_def ILIKE format('%%REFERENCES %s(%s)%%',
'FOO_TABLE','foo_column')
ORDER BY table_schema,table_name,3;
我发现 information_schema.table_constraints
大部分信息来自 pg_constraint
,包括内部参考 OID
,并且有一个内置函数 pg_get_constraintdef()
返回从 OID
.
定义约束对象
然后,定义的一些子字符串足以提取 column_name
AND
使用我在问题中准备的 (I)LIKE
过滤器过滤引用的列。
---------------- 其他答案-----------------
我根据改进@Abelisto 建议构建的另一个可接受的查询:
SELECT table_name, column_name
FROM (SELECT table_name, SUBSTR(column_name, 2, LENGTH(column_name)-2) as column_name,
referenced_table,SUBSTR(referenced_column, 2, LENGTH(referenced_column)-2) as referenced_column
FROM(select
conrelid::regclass::text as table_name,
(select array_agg(attname) from pg_attribute where conrelid = attrelid and attnum = any(conkey))::text as column_name,
confrelid::regclass::text as referenced_table,
(select array_agg(attname) from pg_attribute where confrelid = attrelid and attnum = any(confkey))::text as referenced_column
from pg_constraint where contype = 'f'
) b ) a
WHERE (referenced_table, referenced_column) = 'FOO_TABLE','foo_column');
我认为表演在那里并不重要,所以应该根据副需求来选择。我认为我的第一个解决方案具有获得约束定义的优势,如果你想改变它(例如,添加一个 ON UPDATE CASCADE
子句),但第二个似乎更“紧凑”,只是为了返回table.column.