2014-11-16 2 views
1

У меня есть этот запрос,Используя агрегатную функцию в запросе КТРА

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. Функции окна и т. Д.

Любые указатели будем очень благодарны, спасибо.

UPDATE

Скажем, у меня есть эти таблицы и данные

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); 

Это выход я хотел. Примечание - первый слой не имеет значение (идентификатор 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 

Очевидно, что я хочу, чтобы фактические данные по географии, но думал, что облегчило бы его с только ид сейчас.

+0

Совокупность * после * CTE. Это довольно сложный пример, если вы изучаете этот материал. Вы можете начать с чего-то более простого, такого как список сотрудников и их уровень в иерархии. –

+0

как бы я сделал это после cte? Я пробовал это, но не могу понять, как это сделать, не зацикливая и не имея доступа к агрегированной функции в цикле, не уверен. – Kris

+0

С лучшими базами данных и случайным использованием функций по мере необходимости почти все возможно в SQL. Я приветствую вас за то, что вы выбрали этот маршрут, вместо обработки цикла и обработки одной строки в HLL. Предполагая, что вы создаете качественный SQL и имеете правильные индексы, вы получите лучшую производительность с меньшим объемом кода, запросив базу данных для вашего «набора» данных по одному запросу. Пожалуйста, опишите более подробно, как вы хотите, чтобы этот набор выглядел. –

ответ

1

Редактировать: в этой версии рассматривается ваша проблема с первой версией, не поддерживающей уровень иерархии. Он использует два рекурсивных запроса, где второй отправляет первый. Я никогда не использовал запрос с двумя уровнями рекурсии, и я очень рад, что он работает (по крайней мере, в DB2 и Postgres).

2nd Edit: Я, наконец, смог попасть на 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 
+0

Наверное, я забыл упомянуть, что иерархия может быть произвольной суммой., Поэтому может быть один уровень или 10, поэтому не думайте, что это будет работать. – Kris

+0

Когда вы поймете, как это работает, попробуйте следующее: 1. Сначала просто запустите запрос ассоциаций и поймите его набор результатов. 2.Выполните «выберите * с территорий» рядом, чтобы понять его набор результатов. 3. И наконец, работа над пониманием окончательного запроса, который вырезает только строки, которые вы хотите доставить из набора результатов территорий. Этот процесс является именно тем, как я построил код (в шагах). –

+0

Спасибо, кажется, работает отлично! Бросил в него большой набор данных, и все это имело смысл. – Kris

Смежные вопросы