Много прост пример би бил:
> SELECT * FROM tab ORDER BY col USING <
Но това е скучно, защото това е нищо, което не можете да получите с традиционния ORDER BY col ASC
.
Също така стандартният каталог не споменава нищо вълнуващо за странни функции/оператори за сравнение. Можете да получите списък с тях:
> SELECT amoplefttype::regtype, amoprighttype::regtype, amopopr::regoper
FROM pg_am JOIN pg_amop ON pg_am.oid = pg_amop.amopmethod
WHERE amname = 'btree' AND amopstrategy IN (1,5);
Ще забележите, че има предимно <
и >
функции за примитивни типове като integer
, date
и т.н. и още някои за масиви и вектори и така нататък. Никой от тези оператори няма да ви помогне да получите персонализирана поръчка.
В повечето случаи, когато се изисква персонализирана поръчка, можете да се измъкнете с нещо като ... ORDER BY somefunc(tablecolumn) ...
където somefunc
картографира стойностите по подходящ начин. Тъй като това работи с всяка база данни, това е и най-често срещаният начин. За прости неща можете дори да напишете израз вместо персонализирана функция.
Превключване на предавките нагоре
ORDER BY ... USING
има смисъл в няколко случая:
- Поръчката е толкова необичайна, че
somefunc
трикът не работи. - Работите с непримитивен тип (като
point
,circle
или въображаеми числа) и не искате да се повтаряте в заявките си със странни изчисления. - Наборът от данни, който искате да сортирате, е толкова голям, че е желана или дори необходима поддръжка от индекс.
Ще се съсредоточа върху сложните типове данни:често има повече от един начин да ги сортирате по разумен начин. Добър пример е point
:Можете да ги „подредите“ по разстоянието до (0,0) или по x първо, след това от y или само от y или нещо друго, което искате.
Разбира се, PostgreSQL има предварително дефинирани оператори за point
:
> CREATE TABLE p ( p point );
> SELECT p <-> point(0,0) FROM p;
Но никой от тях е обявен за използваем за ORDER BY
по подразбиране (вижте по-горе):
> SELECT * FROM p ORDER BY p;
ERROR: could not identify an ordering operator for type point
TIP: Use an explicit ordering operator or modify the query.
Прости оператори за point
са операторите "по-долу" и "горе" <^
и >^
. Те сравняват просто y
част от точката. Но:
> SELECT * FROM p ORDER BY p USING >^;
ERROR: operator > is not a valid ordering operator
TIP: Ordering operators must be "<" or ">" members of __btree__ operator families.
ORDER BY USING
изисква оператор с дефинирана семантика:Очевидно трябва да е двоичен оператор, трябва да приема същия тип като аргументи и трябва да връща булев. Мисля, че също трябва да е преходен (ако a btree -подреждане на индекси. Това обяснява странните съобщения за грешка, съдържащи препратка към btree .
ORDER BY USING
също така изисква не само един оператор да бъде дефиниран, но операторен клас и операторско семейство . Докато един може внедрява сортиране само с един оператор, PostgreSQL се опитва да сортира ефективно и да минимизира сравненията. Поради това се използват няколко оператора, дори когато посочите само един – останалите трябва да се придържат към определени математически ограничения – вече споменах транзитивността, но има още.
Превключване на предавките нагоре
Нека дефинираме нещо подходящо:Оператор за точки, който сравнява само y
част.
Първата стъпка е да създадете персонализирано семейство оператори, което може да се използва от btree метод за достъп до индекс. виж
> CREATE OPERATOR FAMILY xyzfam USING btree; -- superuser access required!
CREATE OPERATOR FAMILY
След това трябва да предоставим функция за сравнение, която връща -1, 0, +1 при сравняване на две точки. Тази функция ЩЕ да бъде извикан вътрешно!
> CREATE FUNCTION xyz_v_cmp(p1 point, p2 point) RETURNS int
AS $$BEGIN RETURN btfloat8cmp(p1[1],p2[1]); END $$ LANGUAGE plpgsql;
CREATE FUNCTION
След това дефинираме операторския клас за семейството. Вижте ръководството за обяснение на числата.
> CREATE OPERATOR CLASS xyz_ops FOR TYPE point USING btree FAMILY xyzfam AS
OPERATOR 1 <^ ,
OPERATOR 3 ?- ,
OPERATOR 5 >^ ,
FUNCTION 1 xyz_v_cmp(point, point) ;
CREATE OPERATOR CLASS
Тази стъпка комбинира няколко оператора и функции и също така дефинира тяхната връзка и значение. Например OPERATOR 1
означава:Това е операторът за less-than
тестове.
Сега операторите <^
и >^
може да се използва в ORDER BY USING
:
> INSERT INTO p SELECT point(floor(random()*100), floor(random()*100)) FROM generate_series(1, 5);
INSERT 0 5
> SELECT * FROM p ORDER BY p USING >^;
p
---------
(17,8)
(74,57)
(59,65)
(0,87)
(58,91)
Voila - сортирано по y .
За да обобщим: ORDER BY ... USING
е интересен поглед под капака на PostgreSQL. Но нищо, което няма да ви е необходимо скоро, освен ако не работите в много специфични области на технологията на базата данни.
Друг пример може да се намери в документите на Postgres. с изходен код за примера тук и тук. Този пример също показва как да създадете операторите.