我使用 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
行。由于多种原因,这将是无稽之谈。根据记录,信息模式中的视图“不是”“系统目录”的一部分。但您也不会直接弄乱系统目录 - 即使这可能是可能的。一个错误的举动就会破坏你的数据库(集群)。使用专用的 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_catalog.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 11 添加了过程。您可以对旧版本中的函数执行相同的操作。或者使用
DO
命令在任何版本中一次性使用。参见:
Postgres 中存储过程是否在数据库事务中运行?
表名作为 PostgreSQL 函数参数
IF EXISTS
似乎有点矫枉过正。仅当多个事务可能同时操作列时才有意义,这似乎是一种极其奇怪的情况。