在CTE查询中使用聚合函数

时间:2014-11-16 14:32:06

标签: sql postgresql

我有这个查询

   WITH RECURSIVE territory_data(id,manager_id, name, geography) AS (
      SELECT r.id, r.manager_id, r.name, ST_Union(bd.data)
      FROM hierarchy h
        JOIN reps r ON r.hierarchy_id = h.id
        JOIN rep_sales_area sa ON r.id = sa.rep_id
        JOIN boundary_data bd ON sa.boundary_id = bd.id
      WHERE h.id = 1
      GROUP BY r.id

      UNION ALL 

      SELECT r.id, r.manager_id, r.name, ST_Union(t.geography) as geography
      FROM territory_data t, reps r
      WHERE t.manager_id = r.id 
      GROUP BY r.id 
    )

    select * from territory_data;

基本上我要做的是销售代表控制不同的地区,他们有一个管理员控制他们下属的所有地区。所以基本上走到了链的顶端,执行官将控制整个地图。销售代表只能有1个经理,但经理可以有很多下属。我确信这可以在查询中进行,而不需要在代码中循环,但我是postgres的新手(来自mysql)所以仍然试图找出所有这些更高级的CTE函数..窗口函数等。

非常感谢任何指示,谢谢。

更新

说我有这些表和数据

create table reps (id int NOT NULL primary key, hierarchy_id int NOT NULL,  name varchar(64) NOT NULL, manager_id int );
INSERT INTO reps (id, hierarchy_id, name, manager_id) VALUES 
(1,1, 'John Doe', 6),
(2,1, 'Jane Doe', 7), 
(3, 1, 'Mark Doe', 8), 
(4,1, 'Jake Doe',8),
(5, 1, 'Henry Doe', 6),

(6, 2, 'Derek Smith', 10),
(7, 2, 'Sam Smith', 9),
(8, 2, 'Debby Smith', 9),


(9, 3, 'Carl Burk', null),
(10, 3, 'Adrian Burk', null);


create table hierarchy (id int not null primary key, name varchar(32) NOT NULL);
insert into hierarchy(id, name) values 
(1, 'Sales Reps'),
(2, 'Managers'),
(3, 'Executives');

create table rep_sales_area(id int PRIMARY KEY NOT NULL, rep_id int NOT NULL, boundary_id INT NOT NULL); 
insert into rep_sales_area(id, rep_id, boundary_id) VALUES
(1, 1, 10 ),
(2, 1, 11 ),
(3, 1, 12 ),
(4, 2, 13 ),
(5, 2, 14 ),
(6, 3, 15 ),
(7, 4, 16 ),
(8, 4, 17 ),
(9, 4, 18 ),
(10, 5, 19);

这是我想要的输出。注意 - 如果更容易不包含它,第一层无关紧要(id 1-5)

id | Name        | Manager     | boundaries
1  | John Doe    | Derek Smith | 10, 11, 12
2  | Jane Doe    | Sam Smith   | 13, 14
3  | Mark Doe    | Debby Smith | 15 
4  | Jake Doe    | Debby Smith | 16, 17, 18
5  | Henry Doe   | Derek Smith | 19
6  | Derek Smith | Adrian Buck | 10, 11, 12, 19
7  | Sam Smith   | Carl Buck   | 13, 14
8  | Debby Smith | Carl Buck   | 15, 16, 17, 18
9  | Carl Buck   |             | 13, 14, 15, 16, 17, 18
10 | Adrian Buck |             | 10, 11, 12, 19

显然我想要实际的地理数据,但我认为我现在只用id来简化它。

1 个答案:

答案 0 :(得分:1)

编辑:此版本解决了您对不支持任何层次结构的第一个版本的担忧。它使用两个递归查询,其中第二个以第一个查询为基础。我从未使用过两级递归的查询,并且非常高兴它的工作原理(至少在DB2和Postgres上)。

第二次编辑:我终于能够进入SQLFIDDLE.COM,而不是太忙,并为Postgres 9.3.1而不是之前的DB2版本重构了这个。改变是相当轻微的,以使其快乐。 SQLFIDDLE link

鉴于这是相当复杂的,并且使用一小组数据进行了最低限度的测试,我建议在将其投入生产之前将更多数据集投入其中。

with recursive

associations as (

  select     rep_id as owner_id, boundary_id, id as rep_sales_area_id
  from       rep_sales_area

  union all

  select     s.manager_id as owner_id, a.boundary_id, a.rep_sales_area_id 
  from       associations a
  inner join reps s
        on   s.id = a.owner_id 
  where      s.manager_id is not null
) ,

territories as (

  select     r.id as owner_id
            ,'' as boundary_id_list
            ,0 as rep_sales_area_id
            ,1 as row_num
  from       reps r

  union all 

  select     t.owner_id
            ,trim( t.boundary_id_list ) || case when t.boundary_id_list = '' then '' else ', ' end || n.boundary_id
            ,n.rep_sales_area_id
            ,t.row_num + 1
  from       territories t
  cross join lateral (
    select   a.boundary_id, a.rep_sales_area_id
    from     associations a 
    where    a.rep_sales_area_id > t.rep_sales_area_id
         and a.owner_id = t.owner_id
    order by a.rep_sales_area_id
    limit    1
  ) as n 
)

select     id, name, manager, boundaries
from ( 
  select owner_id as id, r.name, m.name as manager, boundary_id_list as boundaries
        ,row_number() over( partition by owner_id 
                            order by     row_num desc ) as ordered_row_num 
  from       territories t
  left join  reps r
        on   r.id = t.owner_id
  left join  reps m
        on   m.id = r.manager_id
  ) as t

where      ordered_row_num = 1
order by   id