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?
Notes
I prepended all parameters and variables with an underscore (
_) to avoid naming collisions with table columns. Just a useful convention._tcshould bebigint, since that's what the aggregate functioncount()returns.The data type of
_tb_nameis derived from its parent column dynamically:information_schema.tables.table_name%TYPE. See the chapter Copying Types in the manual.Are you sure you only want tables listed in
information_schema.tables? Makes sense, but be aware of implications. See:a_horse already pointed to the manual and Andy provided a code example. This is how you assign a single row or value returned from a dynamic query with
EXECUTEto a (row) variable. A single column (likecountin the example) is decomposed from the row type automatically, so we can assign to the scalar variabletcdirectly - in the same way we would assign a whole row to a record or row variable. Related:Schema-qualify the table name in the dynamic query. There may be other tables of the same name in the current
search_path, which would result in completely wrong (and very confusing!) results without schema-qualification. Sneaky bug! Or this schema is not in thesearch_pathat all, which would make the function raise an exception immediately.Always quote identifiers properly to defend against SQL injection and random errors. Schema and table have to be quoted separately! See:
I use the regular expression operator
~intable_name ~ _tbl_patterninstead oftable_name LIKE ('%' || _tbl_pattern || '%'), that's simpler. Be wary of special characters in the pattern parameter either way! See:I set a default for the schema name in the function call:
_schema text = 'public'. Just for convenience, you may or may not want that. See:Addressing your comment: to pass values, use the
USINGclause like:Related: