Proper solution
... would be partitioning via inheritance. It's rather simple actually. Consider this related answer:
For now
While stuck with your unfortunate design, you can use dynamic SQL in a plpgsql function with EXECUTE
.
Create this function once:
CREATE OR REPLACE FUNCTION f_all_in_schema_foo()
RETURNS SETOF t
LANGUAGE plpgsql AS
$func$
BEGIN
RETURN QUERY EXECUTE (
SELECT string_agg(format('SELECT * FROM %s', c.oid ::regclass)
,E'\nUNION ALL\n'
ORDER BY relname)
FROM pg_namespace n
JOIN pg_class c ON c.relnamespace = n.oid
WHERE n.nspname = 'foo'
AND c.relkind = 'r'
);
END
$func$;
Note how I carefully avoid any possibility for SQL injection (table names have to be considered as "user input"!). See:
Generates and executes a query of the form:
SELECT * FROM foo.p201301
UNION ALL
SELECT * FROM foo.p201302
UNION ALL
SELECT * FROM foo.p201303
UNION ALL
...
Tables are ordered by name due to the ORDER BY
clause in string_agg()
.
You can use this table function just like a table. Call:
SELECT * FROM f_all_in_schema_foo();
Performance should be good.
You can find similar examples with explanation and links here on SO with this search.