Loop through like tables in a schema

て烟熏妆下的殇ゞ 提交于 2019-12-11 05:12:43

问题


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?


回答1:


Proper solution

... would be partitioning via INHERITANCE. It's rather simple actually. Consider this related answer:
Select (retrieve) all records from multiple schemas using Postgres

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 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$  LANGUAGE plpgsql;

Note how I carefully avoid any possibility for SQL injection (table names have to be considered as "user input"!). Consider detailed advice in this related answer:
Table name as a PostgreSQL function parameter
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.




回答2:


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.



来源:https://stackoverflow.com/questions/21144531/loop-through-like-tables-in-a-schema

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!