Question

Postgres 9.1 - I have a schema that has tables "partitioned" by month (a new table is created each month, all columns the same). It is not set up as normal partitioning with a "master" table. I am currently writing a fairly large query, that I will have to run a few times each month.

Schema: augmented_events
tables:
p201301 (January 2013)
p201302 (Feb 2013)
p201303 (March 2013)
...
p201312 (December 2013)
p201401 (January 2014)

Right now I have to write my (simplified) query as:

select *    
from augmented_events.p201301  
union   
select *      
from augmented_events.p201302  
union  
select *      
from augmented_events.p201303  
union  
select *      
from augmented_events.p201312  
union  
select *      
from augmented_events.p201401 

And every month I need to add in the new month. I would like to make this a little more scalable without me having to revisit it every month. Is there a function I can create (or one that exists) that loops through each table in the augmented_events schema, and treats it as if I was to union these tables?

Was it helpful?

Solution

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.

OTHER TIPS

I doubt there's anything like this possible in straight SQL, but you could use outside code (PHP, Perl, .NET; whatever's familiar to you). It would query the schema, drop the old view, and create the new. Schedule it to run daily and you'll be able to use the view without giving a thought to which tables are included.

This is a Band-Aid: better would be to correct this pseudo-partitioning.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top