[PGSQL-RU-GENERAL] Условное упорядочивание по произвольному набору полей

Поиск
Список
Период
Сортировка
От Sergey Konoplev
Тема [PGSQL-RU-GENERAL] Условное упорядочивание по произвольному набору полей
Дата
Msg-id c3a7de1f0802040757q55c5bfdbld0cb22100081666c@mail.gmail.com
обсуждение исходный текст
Список pgsql-ru-general
Добрый день.

Мне часто приходилось сталкиваться с проблемой дублирования одних и
тех же запросов в связи с необходимостью упорядочивания их результатов
по разным наборам полей (разные поля, разное количество полей) в
зависимости от каких-то условий. В случае с маленькими объёмом кода
это решается стандартными средствами, но, когда код выходит за
несколько десятков строк, избыточность часто приводит к не хорошим
последствиям.

Для решения этой проблемы я написал пару операторов:

@< - сортировка в прямом порядке
@> - сортировка в обратном порядке

(см. скрипт во вложении)

Приведу пример того, как с их помощью можно победить избыточность и
придать коду красивый и хорошо читаемый вид. Сначала проблемный код:

if <condition1> then
    for
        select <fields>
        from <tables>
        where <restrictions>
        order by
            field1 desc,
            field2
    loop
        <actions>
    end loop;
elsif <condition2> then
    for
        select <fields>
        from <tables>
        where <restrictions>
        order by
            field3,
            field1 desc,
            field2 desc
    loop
        <actions>
    end loop;
else
    for
        select <fields>
        from <tables>
        where <restrictions>
        order by
            field4
    loop
        <actions>
    end loop;
end if;

Конечно это можно частично обойти за счёт использования курсоров или
динамического SQL, но, сами понимаете, в первом случае избыточность в
запросах никуда не денется, а во втором появятся проблемы со
скоростью. Теперь та же логика, только с использованием новых
операторов:

for
    select <fields>
    from <tables>
    where <restrictions>
    order by
        case when <condition1> then
            @>field1
            @<field2
        when <condition2> then
            @<field3
            @>field1
            @>field2
        else
            @<field4
        end
loop
    <actions>
end loop;

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

select * from (
    values
    (1.2, '2007-11-23 12:00'::timestamp, true),
    (1.4, '2007-11-23 12:00'::timestamp, true),
    (1.2, '2007-11-23 12:00'::timestamp, false),
    (1.4, '2007-01-23 12:00'::timestamp, false),
    (3.5, '2007-08-31 13:35'::timestamp, false)
) _
order by
    @<column1 ||
    case
    when column1 = 1.2 then @<column3
    when column1 = 1.4 then @>column3
    else
        @>column2
        @<column3
    end;

 column1 |       column2       | column3
---------+---------------------+---------
     1.2 | 2007-11-23 12:00:00 | f
     1.2 | 2007-11-23 12:00:00 | t
     1.4 | 2007-11-23 12:00:00 | t
     1.4 | 2007-01-23 12:00:00 | f
     3.5 | 2007-08-31 13:35:00 | f
(5 rows)

Обратите внимание на то, что строки 1-2 и 3-4 имеют разный порядок в
третьей колонке.

p.s. К сожалению операторы пока не работают с текстовыми полями, т.к.
мне ещё не удалось победить локализацию.

--
Regards,
Sergey Konoplev

Вложения

В списке pgsql-ru-general по дате отправления:

Предыдущее
От: silly_sad
Дата:
Сообщение: Re: currval() during one statement
Следующее
От: silly_sad
Дата:
Сообщение: Re: [PGSQL-RU-GENERAL] Условное упорядочивание по произвольному набору полей