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

From: "Sergey Konoplev" <gray(dot)ru(at)gmail(dot)com>
To: pgsql-ru-general(at)postgresql(dot)org
Subject: [PGSQL-RU-GENERAL] Условное упорядочивание по произвольному набору полей
Date: 2008-02-04 15:57:26
Message-ID: c3a7de1f0802040757q55c5bfdbld0cb22100081666c@mail.gmail.com
Views: Raw Message | Whole Thread | Download mbox | Resend email
Thread:
Lists: 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

Attachment Content-Type Size
conditional_ordering.sql application/octet-stream 13.2 KB

Responses

Browse pgsql-ru-general by date

  From Date Subject
Next Message silly_sad 2008-02-05 06:55:25 Re: [PGSQL-RU-GENERAL] Условное упорядочивание по произвольному набору полей
Previous Message silly_sad 2008-01-17 06:40:06 Re: currval() during one statement