9

How can I write a dynamic SELECT INTO query inside a PL/pgSQL function in Postgres?

Say I have a variable called tb_name which is filled in a FOR loop from information_schema.tables. Now I have a variable called tc which will be taking the row count for each table. I want something like the following:

FOR tb_name in select table_name from information_schema.tables where table_schema='some_schema' and table_name like '%1%'
LOOP
EXECUTE FORMAT('select count(*) into' || tc 'from' || tb_name);
END LOOP

What should be the data type of tb_name and tc in this case?

Erwin Brandstetter
  • 605,456
  • 145
  • 1,078
  • 1,228
Karthik
  • 629
  • 2
  • 8
  • 12
  • 1
    See the examples in the manual: https://www.postgresql.org/docs/current/static/plpgsql-statements.html#PLPGSQL-STATEMENTS-EXECUTING-DYN –  Sep 01 '17 at 11:26

2 Answers2

12
CREATE OR REPLACE FUNCTION myfunc(_tbl_pattern text, _schema text = 'public')
  RETURNS void  -- or whatever you want to return
  LANGUAGE plpgsql AS
$func$
DECLARE
   _tb_name information_schema.tables.table_name%TYPE;  -- currently varchar
   _tc      bigint;  -- count() returns bigint
BEGIN
   FOR _tb_name IN
      SELECT table_name
      FROM   information_schema.tables
      WHERE  table_schema = _schema
      AND    table_name   ~ _tbl_pattern  -- see below!
   LOOP
      EXECUTE format('SELECT count(*) FROM %I.%I', _schema, _tb_name)
      INTO _tc;      

      -- do something with _tc
   END LOOP;
END
$func$;

Notes


Addressing your comment: to pass values, use the USING clause like:

EXECUTE format('SELECT count(*) FROM %I.%I
                WHERE some_column = $1', _schema, _tb_name,column_name)
USING user_def_variable;

Related:

Erwin Brandstetter
  • 605,456
  • 145
  • 1,078
  • 1,228
  • EXECUTE format('SELECT count(*) FROM %I.%I', _schema, _tb_name) how can i use a where condition in this select? like EXECUTE format('SELECT count(*) FROM %I.%I WHERE some_column=user_def_variable ', _schema, _tb_name,column_name) – Karthik Sep 04 '17 at 07:07
  • @Karthik: I appended an answer. Please remember to ask questions as *question*. Comments are not the place. – Erwin Brandstetter Sep 04 '17 at 13:54
1

It looks like you want the %I placeholder for FORMAT so that it treats your variable as an identifier. Also, the INTO clause should go outside the prepared statement.

FOR tb_name in select table_name from information_schema.tables where table_schema='some_schema' and table_name like '%1%'
LOOP
  EXECUTE FORMAT('select count(*) from %I', tb_name) INTO tc;
END LOOP
Andy Carlson
  • 3,633
  • 24
  • 43