2013-11-27 40 views
3

我有一个拥有几百个模式的Postgresql 9.1数据库。全部具有相同的结构,只是不同的数据。我需要在表上执行选择并从每个模式获取数据。不幸的是我还没有找到一个体面的方式来做到这一点。Postgresql 9.1从所有模式中选择

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

我设法做到这一点,到目前为止的唯一方法是通过生成就像一个大的查询:

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

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

回答

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 
0

如果你必须知道一些关于表格中的数据,你必须做SELECT。没有其他办法。模式只是逻辑寻址 - 对于你的情况很重要,所以你使用很多表,你必须做大量的联合。

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 
.. 
0

这里有一个方法。您需要预先输入您要定位的所有架构名称。如果你知道你需要每个模式,你可以改变这个来循环所有模式,如Pavel所示。在我的例子中,我有三个模式,我关心每个模式都包含一个名为bar的表。逻辑将在每个模式的条形表上运行一个选择,并将该值插入到结果表中。最后,你有一个表格,包含所有表格的所有数据。你可以改变它来更新,删除或者做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; 
相关问题