postgresql 如果从information_schema.columns中删除某个列,该列是否会被删除?

3okqufwl  于 2023-05-06  发布在  PostgreSQL
关注(0)|答案(1)|浏览(205)

我使用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这样的过滤器。

erhoui1w

erhoui1w1#

不能从information schema中的任何视图DELETE行。这是无稽之谈,原因有很多。需要说明的是,信息模式中的视图 * 不是 * 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_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的数据库事务中运行吗?

这类动态SQL的基础知识:

  • 表名作为PostgreSQL函数参数
  • 在plpgsql函数中定义表名和列名作为参数?
  • 如何检查给定模式中是否存在表

在我们检查了列存在之后,添加IF EXISTS似乎有些多余。只有当多个事务可能并发地操作列时才有意义,这似乎是一种非常奇怪的情况。

相关问题