Thread: [PGSQL-RU-GENERAL] Условное упорядочивание по произвольному набору полей
[PGSQL-RU-GENERAL] Условное упорядочивание по произвольному набору полей
From
"Sergey Konoplev"
Date:
Добрый день. Мне часто приходилось сталкиваться с проблемой дублирования одних и тех же запросов в связи с необходимостью упорядочивания их результатов по разным наборам полей (разные поля, разное количество полей) в зависимости от каких-то условий. В случае с маленькими объёмом кода это решается стандартными средствами, но, когда код выходит за несколько десятков строк, избыточность часто приводит к не хорошим последствиям. Для решения этой проблемы я написал пару операторов: @< - сортировка в прямом порядке @> - сортировка в обратном порядке (см. скрипт во вложении) Приведу пример того, как с их помощью можно победить избыточность и придать коду красивый и хорошо читаемый вид. Сначала проблемный код: 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