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

Mar*_*ato 2 sql postgresql ddl plpgsql postgresql-8.4

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

My_Database
 |-> Schemas
       |-> AccountA
       |-> AccountB
       |-> AccountC
       |-> AccountD
       |-> AccountE
      ...
       |-> AccountZ
Run Code Online (Sandbox Code Playgroud)

所有模式都有一个调用的表product,我想立即为它们添加一个布尔列.是否有可能做到这一点?

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

ALTER TABLE product ADD COLUMN show_price boolean NOT NULL DEFAULT TRUE;
Run Code Online (Sandbox Code Playgroud)

Erw*_*ter 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$
Run Code Online (Sandbox Code Playgroud)

主要观点

  • 正如@Denis已经解释的那样,您可以使用DO语句遍历系统目录表上的条目.但是,这需要Postgres 9.0或更高版本.您也可以创建一个函数(也适用于8.4).该DO语句默认使用过程语言plpgsql.

  • 您需要的唯一系统目录是pg_namespace,保存数据库的模式.循环遍历除已知系统模式之外的所有模式.

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

  • 要向具有NOT NULL约束的表添加列,还必须提供用于填充新列的默认值.其他明智的逻辑上不可能.我DEFAULT TRUE在你的陈述中补充道.根据您的需求调整.

  • 通过引用从系统目录表中检索到的标识符来正确地避免SQL注入.quote_ident()在这种情况下.还有更多选项(dba.SE上的相关答案).

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

    SHOW search_path INTO _text_var;
    ...
    EXECUTE 'SET search_path = ' || _text_var;
    
    Run Code Online (Sandbox Code Playgroud)