plpgsql函数中IF EXISTS内标识符的变量

时间:2013-11-25 12:42:53

标签: postgresql postgresql-9.1 plpgsql dynamic-sql exists

CREATE OR REPLACE FUNCTION drop_now()
  RETURNS void AS
$BODY$
DECLARE
    row     record;
BEGIN
    RAISE INFO 'in';
    FOR row IN 
        select relname from pg_stat_user_tables
        WHERE schemaname='public' AND relname LIKE '%test%'
    LOOP    
    IF EXISTS(SELECT row.relname.tm FROM row.relname
              WHERE row.relname.tm < current_timestamp - INTERVAL '90 minutes'
              LIMIT 1)              
    THEN
    -- EXECUTE 'DROP TABLE ' || quote_ident(row.relname);
    RAISE INFO 'Dropped table: %', quote_ident(row.relname);

    END IF;

    END LOOP;
END;
$BODY$
  LANGUAGE plpgsql VOLATILE;

您能否告诉我如何使用SELECTIF EXISTS内的变量?目前,row.relname.tmrow.relname按字面意思对待,这不是我想要的。

2 个答案:

答案 0 :(得分:1)

CREATE OR REPLACE FUNCTION drop_now()
  RETURNS void AS
$func$
DECLARE
   _tbl   regclass;
   _found int;
BEGIN
   FOR _tbl IN 
      SELECT relid
      FROM   pg_stat_user_tables
      WHERE  schemaname = 'public'
      AND    relname LIKE '%test%'
   LOOP
      EXECUTE format($f$SELECT 1 FROM %s
                        WHERE  tm < now() - interval '90 min'$f$, _tbl);
      GET DIAGNOSTICS _found = ROW_COUNT;
      IF _found > 0 THEN
         -- EXECUTE 'DROP TABLE ' || _tbl;
         RAISE NOTICE 'Dropped table: %', _tbl;
      END IF;
   END LOOP;
END
$func$ LANGUAGE plpgsql;

重点

  • row是SQL标准中的reserved word。 Postgres允许使用它,但它仍然是不明智的。我使用下划线_预先添加psql变量,以避免任何命名冲突。

  • 您无论如何都不会选择整个,只是这个例子中的表名。最好使用regclass类型的变量,从而避免通过非法表名自动注入SQL。这个相关答案的细节:
    Table name as a PostgreSQL function parameter

  • LIMIT表达式中不需要EXISTS,只检查是否存在任何行。而且出于同样的原因,您不需要有意义的目标列。只需写下SELECT 1 or SELECT * or something

  • 对于带有变量标识符的查询,您需要动态SQL 。纯SQL不允许这样做。即:构建一个查询字符串并EXECUTE。这个密切相关答案的细节:
    Dynamic SQL (EXECUTE) as condition for IF statement

  • 如果要运行它,DROP语句也是如此。我添加了评论。

答案 1 :(得分:0)

您需要将查询构建为字符串,然后执行该操作 - 请参阅plpgsql部分of the manual中有关执行动态命令的部分。