Postgresql——如何在具有相同模式的多个表上运行查询

时间:2020-12-27 00:50:49

I have a postgres database that has several tables (a few hundreds). A subset Foo of the tables in the database have the same schema.

我有一个postgres数据库,它有几个表(几百个)。数据库中表的Foo子集具有相同的模式。

Ideally, I would like to create a stored procedure which can run a query against a single table, or against all tables in subset Foo.

理想情况下,我希望创建一个存储过程,它可以对单个表运行查询,也可以对Foo子集中的所有表运行查询。

Pseudocode:

伪代码:

CREATE TABLE tbl_a (id INTEGER, name VARCHAR(32), weight double, age INTEGER);
CREATE TABLE tbl_b (id INTEGER, name VARCHAR(32), weight double, age INTEGER);
CREATE TABLE tbl_c (id INTEGER, name VARCHAR(32), weight double, age INTEGER);
CREATE TABLE tbl_d (id INTEGER, name VARCHAR(32), weight double, age INTEGER);

CREATE TYPE person_info AS (id INTEGER, name VARCHAR(32), weight double, age INTEGER);

CREATE FUNCTION generic_func(ARRAY one_or_more_table_names)
    RETURNS person_info 
    -- Run query on table or all specified tables
    AS $$  $$
    LANGUAGE SQL; 

How could I implement this requirement in Postgresql 9.x ?

我如何在Postgresql 9中实现这个需求。x ?

2 个解决方案

#1


2  

You should have a look at table inheritance in PostgreSQL, they allow exactly what you speak about.

您应该看看PostgreSQL中的表继承,它们完全允许您所说的内容。

For example, you could create a table parent_tbl:

例如,可以创建一个parent_tbl表:

CREATE TABLE parent_tbl (id INTEGER, name VARCHAR(32), weight numeric, age INTEGER);

Then link your tables to this parent table:

然后将表链接到父表:

ALTER TABLE tbl_a INHERIT parent_tbl;
ALTER TABLE tbl_b INHERIT parent_tbl;
ALTER TABLE tbl_c INHERIT parent_tbl;
ALTER TABLE tbl_d INHERIT parent_tbl;

Then a SELECT query over parent_tbl will query all of tbl_x tables, while a query on tbl_x will query only this particular table.

然后,parent_tbl上的SELECT查询将查询所有tbl_x表,而tbl_x上的查询将只查询这个特定的表。

INSERT INTO tbl_a VALUES (1, 'coucou', 42, 42);

SELECT * FROM tbl_a;
 id |  name  | weight | age 
----+--------+--------+-----
  1 | coucou |     42 |  42
(1 row)

SELECT * FROM parent_tbl;
 id |  name  | weight | age 
----+--------+--------+-----
  1 | coucou |     42 |  42
(1 row)

SELECT * FROM tbl_b;
 id |  name  | weight | age 
----+--------+--------+-----
(0 rows)

It is also possible to filter data from given children tables. For example, if you are interested in data coming from tables tbl_a and tbl_b, you can do

也可以从给定的子表中过滤数据。例如,如果您对来自表tbl_a和tbl_b的数据感兴趣,您可以这样做。

select id, name, weight, age
from parent_tbl
left join pg_class on oid = parent_tbl.tableoid
where relname in ('tbl_a', 'tbl_b');

EDIT : I put numeric for weight instead of double as this type is not supported on my server.

编辑:我将数值表示权重,而不是双精度,因为我的服务器不支持这种类型。

#2


2  

To create select query dynamically using items(table name) in an array you can use following select statement

要使用数组中的项(表名)动态创建select查询,可以使用以下select语句

SELECT string_agg(q, ' union all ')
FROM  (
    SELECT 'select * from ' || unnest(array ['tble_a','tble_b']) AS q
    ) t

Result:

结果:

string_agg                                          
--------------------------------------------------- 
select * from tble_a union all select * from tble_b 

You can create the function that returns table with columns

您可以创建返回带有列的表的函数

 id INTEGER
,name VARCHAR(32)
,weight numeric
,age INTEGER

P.S: I am avoiding TYPE person_info

P。S:我在避免键入person_info。

function:

功能:

CREATE
    OR REPLACE FUNCTION generic_func (tbl varchar [])
RETURNS TABLE (         -- To store the output
        id INTEGER
        ,name VARCHAR(32)
        ,weight numeric
        ,age INTEGER
        ) AS $BODY$

DECLARE qry text;

BEGIN
    SELECT string_agg(q, ' union all ')  --To create select query dynamically
    INTO qry
    FROM (
        SELECT 'select * from ' || unnest(tbl) AS q
        ) t;

    RAISE NOTICE 'qry %',qry; --optional

    RETURN query --Executes the query to the defined table

    EXECUTE qry;
END;$BODY$

LANGUAGE plpgsql VOLATILE

Usage:

用法:

select * from generic_func(array['tbl_a','tbl_b','tbl_c','tbl_d'])

Result:

结果:

id name weight age 
-- ---- ------ --- 
2  ABC  11     112 
2  CBC  11     112 
2  BBC  11     112 
2  DBC  11     112 

and

select * from generic_func(array['tbl_a'])

select * from generic_func(array[' tbl_a '])

Result:
id name weight age 
-- ---- ------ --- 
2  ABC  11     112 

#1


2  

You should have a look at table inheritance in PostgreSQL, they allow exactly what you speak about.

您应该看看PostgreSQL中的表继承,它们完全允许您所说的内容。

For example, you could create a table parent_tbl:

例如,可以创建一个parent_tbl表:

CREATE TABLE parent_tbl (id INTEGER, name VARCHAR(32), weight numeric, age INTEGER);

Then link your tables to this parent table:

然后将表链接到父表:

ALTER TABLE tbl_a INHERIT parent_tbl;
ALTER TABLE tbl_b INHERIT parent_tbl;
ALTER TABLE tbl_c INHERIT parent_tbl;
ALTER TABLE tbl_d INHERIT parent_tbl;

Then a SELECT query over parent_tbl will query all of tbl_x tables, while a query on tbl_x will query only this particular table.

然后,parent_tbl上的SELECT查询将查询所有tbl_x表,而tbl_x上的查询将只查询这个特定的表。

INSERT INTO tbl_a VALUES (1, 'coucou', 42, 42);

SELECT * FROM tbl_a;
 id |  name  | weight | age 
----+--------+--------+-----
  1 | coucou |     42 |  42
(1 row)

SELECT * FROM parent_tbl;
 id |  name  | weight | age 
----+--------+--------+-----
  1 | coucou |     42 |  42
(1 row)

SELECT * FROM tbl_b;
 id |  name  | weight | age 
----+--------+--------+-----
(0 rows)

It is also possible to filter data from given children tables. For example, if you are interested in data coming from tables tbl_a and tbl_b, you can do

也可以从给定的子表中过滤数据。例如,如果您对来自表tbl_a和tbl_b的数据感兴趣,您可以这样做。

select id, name, weight, age
from parent_tbl
left join pg_class on oid = parent_tbl.tableoid
where relname in ('tbl_a', 'tbl_b');

EDIT : I put numeric for weight instead of double as this type is not supported on my server.

编辑:我将数值表示权重,而不是双精度,因为我的服务器不支持这种类型。

#2


2  

To create select query dynamically using items(table name) in an array you can use following select statement

要使用数组中的项(表名)动态创建select查询,可以使用以下select语句

SELECT string_agg(q, ' union all ')
FROM  (
    SELECT 'select * from ' || unnest(array ['tble_a','tble_b']) AS q
    ) t

Result:

结果:

string_agg                                          
--------------------------------------------------- 
select * from tble_a union all select * from tble_b 

You can create the function that returns table with columns

您可以创建返回带有列的表的函数

 id INTEGER
,name VARCHAR(32)
,weight numeric
,age INTEGER

P.S: I am avoiding TYPE person_info

P。S:我在避免键入person_info。

function:

功能:

CREATE
    OR REPLACE FUNCTION generic_func (tbl varchar [])
RETURNS TABLE (         -- To store the output
        id INTEGER
        ,name VARCHAR(32)
        ,weight numeric
        ,age INTEGER
        ) AS $BODY$

DECLARE qry text;

BEGIN
    SELECT string_agg(q, ' union all ')  --To create select query dynamically
    INTO qry
    FROM (
        SELECT 'select * from ' || unnest(tbl) AS q
        ) t;

    RAISE NOTICE 'qry %',qry; --optional

    RETURN query --Executes the query to the defined table

    EXECUTE qry;
END;$BODY$

LANGUAGE plpgsql VOLATILE

Usage:

用法:

select * from generic_func(array['tbl_a','tbl_b','tbl_c','tbl_d'])

Result:

结果:

id name weight age 
-- ---- ------ --- 
2  ABC  11     112 
2  CBC  11     112 
2  BBC  11     112 
2  DBC  11     112 

and

select * from generic_func(array['tbl_a'])

select * from generic_func(array[' tbl_a '])

Result:
id name weight age 
-- ---- ------ --- 
2  ABC  11     112