我使用 Postgres 14。我知道
ALTER TABLE DROP COLUMN
。但这个选项对我来说并不适用。
这两个查询是否相等:
ALTER TABLE <some_table_1>
DROP COLUMN IF EXISTS <column_1>,
DROP COLUMN IF EXISTS <column_2>;
ALTER TABLE <some_table_2>
DROP COLUMN IF EXISTS <column_1>,
DROP COLUMN IF EXISTS <column_2>;
和
DELETE FROM information_schema.columns
WHERE table_name IN (<some_table_1>, <some_table_2>) AND column_name IN (<column_1>, <column_2>)
或者
ALTER TABLE
做一些额外的工作?我想使用DELETE FROM
,因为我真的需要在列删除中像WHERE
这样的过滤器。
您不能
DELETE
information schema 中任何视图的行。出于多种原因,这将是无稽之谈。作为记录,信息模式中的视图 not system catalogs 的一部分。但是您也不要直接弄乱系统目录——即使这可能是可能的。一个错误的举动,你可以破坏你的数据库(集群)。使用专用的 DDL 命令。
您正在寻找 动态 SQL - 它可以基于:信息模式或系统目录。每个都有优点和缺点。参见:
我的实现使用系统目录:
CREATE OR REPLACE PROCEDURE public.my_column_drop(_tbls text[]
, _cols text[]
, _schema text = 'public')
LANGUAGE plpgsql AS
$proc$
DECLARE
_tbl regclass;
_drops text;
BEGIN
FOR _tbl IN
SELECT c.oid
FROM pg_class c
WHERE c.relkind = 'r' -- only plain tables (?)
AND c.relnamespace = _schema::regnamespace
AND c.relname = ANY (_tbls)
-- more filters HERE
LOOP
-- RAISE NOTICE '%', _tbl;
SELECT INTO _drops
string_agg(format('DROP COLUMN IF EXISTS %I', a.attname), ', ')
FROM pg_catalog.pg_attribute a
WHERE a.attrelid = _tbl
AND a.attname = ANY (_cols)
AND NOT a.attisdropped
AND a.attnum > 0
-- more filters HERE
;
IF _drops IS NOT NULL THEN
-- RAISE NOTICE '%', concat_ws(' ', 'ALTER TABLE', _tbl, _drops);
EXECUTE concat_ws(' ', 'ALTER TABLE', _tbl, _drops);
ELSE
RAISE NOTICE 'Table % has no candidate columns', _tbl;
END IF;
END LOOP;
END
$proc$;
电话:
CALL public.my_column_drop ('{some_table_1,some_table_2}', '{column_1, column_2}');
如果存在任何依赖关系,删除列的尝试将失败。我的简单功能不会检查那些。您必须定义要检查的内容以及在依赖项的情况下要做什么......
过程是在 Postgres 12 中添加的。您可以对旧版本中的函数执行相同的操作。参见:
这种动态 SQL 的基础知识:
在我们检查该列是否存在后,添加
IF EXISTS
似乎有点矫枉过正。仅当多个事务可能同时操作列时才有意义,这似乎是一个非常奇怪的情况。