在PostgreSQL数据库的所有模式中向表中添加一列

时间:2013-11-28 19:04:32

标签: sql postgresql plpgsql ddl postgresql-8.4

我有一个Postgres 8.4架构,如下所示:

My_Database
 |-> Schemas
       |-> AccountA
       |-> AccountB
       |-> AccountC
       |-> AccountD
       |-> AccountE
      ...
       |-> AccountZ

所有模式都有一个名为product的表,我想立即为它们添加一个布尔列。有可能这样做吗?

我到目前为止找到的唯一方法是按帐户运行以下SQL帐户。

ALTER TABLE product ADD COLUMN show_price boolean NOT NULL DEFAULT TRUE;

2 个答案:

答案 0 :(得分:6)

DO
$do$
DECLARE
  _schema text;
  _sp
BEGIN

FOR _schema IN
    SELECT quote_ident(nspname)  -- prevent SQL injection
    FROM   pg_namespace n
    WHERE  nspname !~~ 'pg_%'
    AND    nspname <>  'information_schema'
LOOP
   EXECUTE 'SET LOCAL search_path = ' || _schema;
   ALTER TABLE product ADD COLUMN show_price boolean NOT NULL DEFAULT TRUE;
END LOOP;

END
$do$

重点

  • 作为@Denis already explained,您可以使用DO statement遍历系统目录表上的条目。但是,这需要 Postgres 9.0或更高版本。 你也可以create a function也适用于8.4 )。 DO语句默认使用procedural language plpgsql

  • 您需要的唯一系统目录是pg_namespace,其中包含数据库的模式。循环遍历除已知系统模式之外的所有模式。

  • 确保您已连接到正确的数据库!

  • 要向具有 NOT NULL 约束的表添加列,您还必须提供用于填充新列的默认值。其他明智的逻辑上不可能。我在您的对帐单中添加了 DEFAULT TRUE 。根据您的需求进行调整。

  • 通过引用从系统目录表中检索到的标识符来正确地避免SQL注入。在这种情况下quote_ident()There are more options (related answer on dba.SE)

  • 您需要动态SQL。我的主要技巧是动态设置search_path,因此可以反复运行相同的语句。 SET LOCAL的效果持续到交易结束。您可以使用RESET search_path或保存先前状态并重置它,如果您需要在同一事务中执行更多操作(不太可能):

    SHOW search_path INTO _text_var;
    ...
    EXECUTE 'SET search_path = ' || _text_var;
    

答案 1 :(得分:1)

无论如何,你都需要这样做。

您可以做的是通过查询目录来自动化它,然后将代码包装在do block(Postgres 9.0或更高版本中)或使用迁移脚本。如果您不熟悉查询目录,要查找所需的查询,最简单的方法是使用psql -E。它会显示在您输入\dn\dt时运行的隐藏查询。