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