2016-04-14 40 views
2

假设我有以下表格:如何查询树结果的Postgres设置包括多个表

drop table if exists city; 
drop table if exists country; 
drop table if exists world; 

create table world (
    id integer PRIMARY KEY, 
    name text not null, 
    population bigint not null 
) 
; 
create table country (
    id integer PRIMARY KEY, 
    world_id integer REFERENCES world (id), 
    name text not null, 
    population bigint not null 
); 

create table city (
    id integer PRIMARY KEY, 
    country_id integer REFERENCES country (id), 
    name text not null, 
    population bigint not null 
); 

insert into world (id, name, population) values (1, 'World', 7125000000); 
insert into country (id, world_id, name, population) values (2, 1, 'Austria', 8000000); 
insert into country (id, world_id, name, population) values (3, 1, 'Poland', 38530000); 
insert into city (id, country_id, name, population) values (4, 2, 'Vienna', 1741000); 
insert into city (id, country_id, name, population) values (5, 2, 'Salzburg', 145000); 
insert into city (id, country_id, name, population) values (6, 3, 'Warsaw', 1710000); 
insert into city (id, country_id, name, population) values (7, 3, 'Stetin', 409000); 

所以基本上在使用被互相连接3台世界上一个非常简化的视图。现在,为了得到我所需要的所有信息,我可以简单地执行查询像

select 
    w.name, 
    c.name, 
    ci.name 
from 
    world w 
    left outer join country c on (w.id = c.world_id) 
    left outer join city ci on (c.id = ci.country_id) 

这给我回了必要的数据:

name | name | name 
-------+---------+---------- 
World | Austria | Vienna 
World | Austria | Salzburg 
World | Poland | Warsaw 
World | Poland | Stetin 

对于这样一个小例子,数据复制在结果集中可能没关系。尽管如此,在我的真实世界中,结果集要大得多(200k行),并且需要查询更多的列。由于整个结构的树形结构的提醒,我想知道,如果有可能建立一个结果集看起来更像这个有点:

id | parent | name | population 
-------+----------+----------+------------ 
1  | null  | World | 7125000000 
2  | 1  | Austria | 8000000 
3  | 1  | Poland | 38530000 
4  | 2  | Vienna | 1741000 
5  | 2  | Salzburg |  145000 
6  | 3  | Warsaw | 1710000 
7  | 3  | Stetin |  409000 

所有ID都是不同的表中是唯一的。只有一个表来表示和构建树结果集,我读过,可以使用with-queries,但到目前为止,我没有找到任何有关如何实现这个涉及多个表的任何表。

回答

1

您首先需要在所有三个表格上创建一个“统一”视图,例如,像这样:

select id, null, name, population 
from world 
union all 
select id, world_id, name, population 
from country 
union all 
select id, country_id, name, population 
from city 

这可以被用于构建遍历树递归公用表表达式:

with recursive regions (id, parent_id, name, population) as (
    select id, null, name, population 
    from world 
    union all 
    select id, world_id, name, population 
    from country 
    union all 
    select id, country_id, name, population 
    from city 
), region_tree as (
    select id, parent_id, name, population 
    from regions 
    where parent_id is null 
    union all 
    select c.id, c.parent_id, c.name, c.population 
    from regions c 
    join region_tree p on p.id = c.parent_id 
) 
select * 
from area_tree; 

如果你需要这种查询了很多,这可能是更好的存储所有东西都在单个表中,列中列出了为什么种类的“区域”行(世界,国家,城市)。这也将导致更容易引入新的“区域类型”(县,州等),例如:

create table region 
(
    id integer primary key, 
    parent_id integer references region, 
    name text, 
    population integer, 
    type text not null check (type in ('world','country','city')) 
); 
+0

这些表仍然通过外键“连接”,并且它可以仅查询子树(让我们说一切在波兰之下)? – u6f6o

+0

我也想过有一个带有鉴别器的表格,但遗憾的是我无法轻松地在我们的产品系统上做出这样的模式变更。 – u6f6o

+0

@ u6f6o:只需查询子树,就可以更改第二个CTE的非递归部分的条件,例如, 'name ='Poland''而不是'parent_id为null' –

相关问题