2012-02-11 3 views
2

Условия: PostgreSQL 8.4 (это было бы слишком просто с 9.x)PostgreSQL: Каков наилучший способ сортировки нескольких array_agg() с разными условиями?

Таблица:

id | gpa | class | rank 
    ----+-----+---------+-------- 
    1 | 2.0 | english | low 
    1 | 2.0 | math | low 
    1 | 2.0 | pe  | low 
    1 | 2.0 | spanish | medium 
    2 | 3.5 | english | high 
    2 | 3.5 | history | high 
    2 | 3.5 | art  | great 
    2 | 3.5 | tech | high 
    3 | 4.0 | pe  | medium 
    3 | 4.0 | spanish | high 
    3 | 4.0 | english | great 
    3 | 4.0 | art  | great 

Требуются:

id | gpa | great  |   high   | medium | low 
    ----+-----+--------------+------------------------+---------+----- 
    1 | 2.0 |    |      | spanish | english, math, pe 
    2 | 3.5 | art   | english, history, tech |   | 
    3 | 4.0 | art, english | spanish    | pe  | 

Текущий метод:

WITH details AS (
    select * from table order by rank, class 
) 
SELECT id 
     , gpa 
     , array_to_string(array_agg(CASE WHEN rank='great' THEN class END,', ')) as great 
     , array_to_string(array_agg(CASE WHEN rank='high' THEN class END,', ')) as high 
     , array_to_string(array_agg(CASE WHEN rank='medium' THEN class END,', ')) as medium 
     , array_to_string(array_agg(CASE WHEN rank='low' THEN class END,', ')) as low 
FROM  details 
ORDER BY gpa; 

Так Я попытался привести это в качестве примера из того, что я делаю - нет, у меня нет фактическая таблица с этой структурой, которая не очень нормализована, но у меня есть подзапрос, который производит что-то вроде этого.

В действительности мой массив_agg() также объединяет два поля (слово и число), и я сортирую по числу, например (array_agg(CASE ... THEN foo || ' - ' || bar), к сожалению, мой вывод только в основном отсортирован. Возможно, я смогу улучшить этот вопрос, если у меня будет больше времени.

ответ

1

Когда я выполнить этот запрос:

with details AS (
    select * from table order by class 
) 
select t.id, t.gpa, 
    (select array_to_string(array_agg(class),',') 
    from details d 
    where d.id = t.id and d.gpa = t.gpa and rank = 'great') 
    as great, 
    (select array_to_string(array_agg(class),',') 
    from details d 
    where d.id = t.id and d.gpa = t.gpa and rank = 'high') 
    as high, 
(select array_to_string(array_agg(class),',') 
    from details d 
    where d.id = t.id and d.gpa = t.gpa and rank = 'medium') 
as medium, 
(select array_to_string(array_agg(class),',') 
    from details d 
    where d.id = t.id and d.gpa = t.gpa and rank = 'low') 
    as low 
from table t 
group by t.id, t.gpa 
order by t.gpa 

я получаю результаты:

id gpa  great   high     medium  low 
----+-----+-------------+----------------------+----------+------------------ 
    1 2.0           spanish english,math,pe 
    2 3.5  art  english,history,tech 
    3 4.0 art,english spanish     pe 

Надеюсь, вы служите.

ОБНОВЛЕНИЕ: Другие варианты с лучшей производительностью.

select t.id, t.gpa, 
     a.class as great, 
     b.class as high, 
     c.class as medium, 
     d.class as low 
from table t 
left join (select id, gpa, array_to_string(array_agg(class),',') as class 
      from table 
      where rank = 'great' 
      group by id, gpa 
     ) a on (a.id = t.id and a.gpa = t.gpa) 
left join (select id, gpa, array_to_string(array_agg(class),',') as class 
      from table 
      where rank = 'high' 
      group by id, gpa 
     ) b on (b.id = t.id and b.gpa = t.gpa) 
left join (select id, gpa, array_to_string(array_agg(class),',') as class 
      from table 
      where rank = 'medium' 
      group by id, gpa 
     ) c on (c.id = t.id and c.gpa = t.gpa) 
left join (select id, gpa, array_to_string(array_agg(class),',') as class 
      from table 
      where rank = 'low' 
      group by id, gpa 
      ) d on (d.id = t.id and d.gpa = t.gpa)   
group by t.id, t.gpa, a.class, b.class, c.class, d.class 
order by t.gpa 
+0

Итак, это то, о чем я изначально думал, но разве у него не было бы большого успеха? Он запускает 4 запроса для каждой записи. – vol7ron

+0

Привет @ vol7ron, вы правы. Это не самый лучший вариант из-за огромного успеха. Однако я читал, что, возможно, у вас нет разрешения на создание функции. Если вы подтвердите, что у вас есть это, я могу написать другие варианты с лучшей производительностью. – doctore

+0

@ vol7ron, я просто обновляю ответ вторым запросом с лучшей производительностью. – doctore

1

Создание функции, как:

create or replace function sort(anyarray) returns anyarray language sql as 
$$ 
    select array_agg(x) from(
     select unnest($1) as x order by 1 
    ) tab; 
$$; 

, а затем:

... 
array_to_string(sort(array_agg(CASE WHEN rank='great' THEN class END,', '))) 
... 
+0

Итак, в основном подзапросы сортируются. не знаю, какие разрешения у меня есть, я проверю, могу ли я создать функцию. – vol7ron

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