Postgresql 9.1从所有模式中选择

时间:2013-11-27 08:42:57

标签: postgresql schema

我有一个包含几百个模式的Postgresql 9.1数据库。所有都有相同的结构,只是不同的数据。我需要在表上执行select并从每个模式获取数据。不幸的是,我没有找到一个体面的方法来做到这一点。

我尝试将搜索路径设置为schema_1,schema_2等,然后对表执行select,但它只选择第一个模式中的数据。

到目前为止,我设法做到的唯一方法是生成一个大查询,如:

select * from schema_1.table
union
select * from schema_2.table
union
(...another 100 lines....)

还有其他方法以更合理的方式做到这一点吗?如果无法做到这一点,我是否至少可以在不执行此选择的情况下找出哪个模式在该表中有记录?

3 个答案:

答案 0 :(得分:1)

不同的模式意味着不同的表格,所以如果你必须坚持这种结构,它将意味着工会,不管是哪种方式。这可能相当昂贵。如果您通过搜索路径的方便进行分区,则可能有必要撤消您的架构:

在公共模式中存储一个大表,然后在每个模式中配置视图。

查看这个展示我的概念的sqlfiddle:

http://sqlfiddle.com/#!12/a326d/1

如果sqlfiddle无法访问,也会为后代粘贴内联:

架构:

CREATE SCHEMA customer_1;
CREATE SCHEMA customer_2;

CREATE TABLE accounts(id serial, name text, value numeric, customer_id int);
CREATE INDEX ON accounts (customer_id);

CREATE VIEW customer_1.accounts AS SELECT id, name, value FROM public.accounts WHERE customer_id = 1;
CREATE VIEW customer_2.accounts AS SELECT id, name, value FROM public.accounts WHERE customer_id = 2;

INSERT INTO accounts(name, value, customer_id) VALUES('foo', 100, 1);
INSERT INTO accounts(name, value, customer_id) VALUES('bar', 100, 1);
INSERT INTO accounts(name, value, customer_id) VALUES('biz', 150, 2);
INSERT INTO accounts(name, value, customer_id) VALUES('baz', 75, 2);

查询:

SELECT SUM(value) FROM public.accounts;

SET search_path TO 'customer_1';
SELECT * FROM accounts;

SET search_path TO 'customer_2';
SELECT * FROM accounts;

结果:

425

1   foo     100
2   bar     100

3   biz     150
4   baz     75

答案 1 :(得分:0)

如果您必须了解表中的数据,则必须执行SELECT。没有别的办法。 Schema只是逻辑寻址 - 对于你的情况很重要,所以你使用了很多表,你必须做大量的UNION。

search_path按预期工作。它没有任何意义 - 从提到的方案返回数据,但它指定了搜索不完全限定表的顺序。搜索以第一个表结束,该表已请求名称。

注意:大规模的工会需要大量的记忆。

您可以将动态SQL和存储过程与临时表一起使用:

postgres=# DO $$
   declare r record;
   begin
     drop table if exists result;
     create temp table result as select * from x.a limit 0; -- first table;
     for r in select table_schema, table_name
                  from information_schema.tables
                 where table_name = 'a'
     loop
       raise notice '%', r;
       execute format('insert into result select * from %I.%I',
                                          r.table_schema,
                                          r.table_name);
     end loop;
   end; $$;

结果:

NOTICE:  (y,a)
NOTICE:  (x,a)
DO
postgres=# select * from result;
 a  
----
  1
  2
  3
  4
  5
 ..

答案 2 :(得分:0)

这是一种方法。您需要预先提供您要定位的所有架构名称。您可以将此更改为仅循环遍历所有模式,如Pavel所示,如果您知道您想要每个模式。在我的例子中,我有三个我关心的模式,每个模式包含一个名为bar的表。逻辑将在每个模式的条形表上运行select,并将值插入结果表中。最后,您有一个表格,其中包含所有表格中的所有数据。您可以将其更改为更新,删除或执行DDL。我选择保持简单,只收集每个模式中每个表的数据。

--START SETUP AKA Run This Section Once
create table schema3.bar(bar_id   SERIAL PRIMARY KEY,
                         bar_name VARCHAR(50) NOT NULL);

insert into schema1.bar(bar_name) select 'One';
insert into schema2.bar(bar_name) select 'Two';
insert into schema3.bar(bar_name) select 'Three';
--END SETUP

DO $$
   declare r record;
   DECLARE l_id INTEGER = 1;
   DECLARE l_schema_name TEXT;
   begin
     drop table if exists public.result;
     create table public.result (bar_id INTEGER, bar_name TEXT);

     drop table if exists public.schemas;
     create table public.schemas (id serial PRIMARY KEY, schema_name text NOT NULL);
     INSERT INTO public.schemas(schema_name)
     VALUES ('schema1'),('schema2'),('schema3');


     for r in select *
              from public.schemas 
     loop
       raise notice '%', r;

       SELECT schema_name into l_schema_name
       FROM public.schemas
       WHERE id = l_id;

       raise notice '%', l_schema_name;
       EXECUTE 'set search_path TO ' || l_schema_name;

      EXECUTE 'INSERT into public.result(bar_id, bar_name) select bar_id, bar_name from ' || l_schema_name || '.bar';

       l_id = l_id + 1;
     end loop;

   end; $$;


--DEBUG
   select * from schema1.bar;
   select * from schema2.bar;
   select * from schema3.bar;

   select * from public.result;
   select * from public.schemas;

   --CLEANUP
   --DROP TABLE public.result;
   --DROP TABLE public.schemas;