【问题标题】:Postgresql - how to run a query on multiple tables with same schemaPostgresql - 如何在具有相同架构的多个表上运行查询
【发布时间】:2017-05-19 18:23:32
【问题描述】:

我有一个包含多个表(几百个)的 postgres 数据库。数据库中表的子集 Foo具有相同的架构。

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

伪代码:

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; 

如何在 Postgresql 9.x 中实现这个要求?

【问题讨论】:

  • 不相关,但是:“Postgres 9.x”涵盖了 7 个不同的主要版本(其中两个不再支持)。您需要更具体地使用 Postgres 版本。

标签: sql postgresql stored-procedures dynamic-sql


【解决方案1】:

你应该看看 PostgreSQL 中的table inheritance,它们完全允许你所说的。

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

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

然后将你的表链接到这个父表:

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;

然后对 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)

也可以从给定的子表中过滤数据。例如,如果您对来自表 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');

编辑:我将数字作为重量而不是双精度,因为我的服务器不支持这种类型。

【讨论】:

  • +1 对于我需要在所有表上运行查询的用例的简洁解决方案,但在我需要在特定表上运行的情况下,我需要对某些重复相同的代码300 多张桌子!从那以后我发现将表的名称传递给查询是不好的形式。有没有一种方法可以让我引入另一个表并使用 JOINS 来限制在父表上运行的查询,仅限于 table_a 中的数据?
  • 当然!您可以使用 tableoid 列。我会更新我的答案,请给我 5 分钟时间
  • 谢谢!,我在您的 Postgresqlfu 面前谦卑地鞠躬! ;)
【解决方案2】:

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

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

结果:

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

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

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

P.S:我避免TYPE person_info

功能:

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

用法:

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

结果:

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

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

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

【讨论】:

  • +1 我喜欢这个,因为它允许我指定表的名称。但是,我后来发现这被认为是一种反模式 (stackoverflow.com/questions/10705616/…)。因此,我目前更倾向于 Fabian 的答案——它相当优雅地满足了“多表查询”的要求——但看起来很笨拙(要求每个表都有自己的查询“版本”,其中表名在查询/SP 中硬编码。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多