如何保持循环甚至错误发生?

时间:2015-11-21 16:47:21

标签: postgresql plpgsql postgresql-9.3

我写了一个PL / pgsql来批量创建表的索引

CREATE OR REPLACE FUNCTION create_index() RETURNS void AS
$BODY$
DECLARE
    r INTEGER;
BEGIN
    FOR r IN 1..1000
    LOOP
        EXECUTE format(
        ' CREATE INDEX idx_abc_id_' || r::text ||
        ' ON abc_id_' || r::text ||
        ' USING btree
        (key);');
    END LOOP;
    RETURN;
END
$BODY$
LANGUAGE plpgsql;

它有一个问题,如果分区abc_500不存在,那么create index函数将如何失败并且什么都不做。

即使create_index在其中一个表上发生错误,如何让循环继续进行?

1 个答案:

答案 0 :(得分:2)

我认为更好的方法是不对循环的数字进行硬编码,而是迭代现有的表:

CREATE OR REPLACE FUNCTION create_index() RETURNS void AS
$BODY$
DECLARE
    r record;
BEGIN
  FOR r IN select tablename, regexp_replace(tablename, '[^0-9]+','') as idx_nr
            from pg_tables
            where tablename ~ 'abc_id_[0-9]+'
  LOOP
    EXECUTE format('CREATE INDEX %I ON %I USING btree (key)', 
                   'idx_abc_id_'||r.idx_nr, 
                   r.tablename);
  END LOOP;
  RETURN;
END
$BODY$
LANGUAGE plpgsql;

当您使用format()功能时,最好使用适当的占位符作为标识符。

如果您还想在现有表上创建索引时忽略任何错误,则需要捕获异常并忽略它:

CREATE OR REPLACE FUNCTION create_index() RETURNS void AS
$BODY$
DECLARE
    r record;
    msg text;
BEGIN
  FOR r IN select tablename, regexp_replace(tablename, '[^0-9]+','') as idx_nr
           from pg_tables
           where tablename ~ 'abc_id_[0-9]+'
  LOOP
    BEGIN
      EXECUTE format('CREATE INDEX %I ON %I USING btree (key)', 
                     'idx_abc_id_'||r.idx_nr, 
                      r.tablename);
    EXCEPTION 
      WHEN OTHERS THEN
        GET STACKED DIAGNOSTICS msg = MESSAGE_TEXT;      
        RAISE NOTICE 'Could not create index for: %, %', r.idx_nr, msg;
    END;
  END LOOP;
  RETURN;
END
$BODY$
LANGUAGE plpgsql;