Bardzo prostym przykładem byłoby:
> SELECT * FROM tab ORDER BY col USING <
Ale to jest nudne, ponieważ to nic, czego nie można uzyskać za pomocą tradycyjnego ORDER BY col ASC
.
Również standardowy katalog nie wspomina nic ekscytującego o dziwnych funkcjach/operatorach porównania. Możesz otrzymać ich listę:
> 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);
Zauważysz, że w większości są to <
i > funkcje dla typów pierwotnych, takich jak
integer
, data
itd. i jeszcze trochę dla tablic i wektorów i tak dalej. Żaden z tych operatorów nie pomoże Ci uzyskać niestandardowego zamówienia.
W większości przypadki, w których wymagane jest niestandardowe zamówienie, możesz uciec, używając czegoś takiego jak ... ORDER BY somefunc(tablecolumn) ...
gdzie jakaśfunkcja
odpowiednio mapuje wartości. Ponieważ działa to z każdą bazą danych, jest to również najczęstszy sposób. W przypadku prostych rzeczy możesz nawet napisać wyrażenie zamiast funkcji niestandardowej.
Zmiana biegów w górę
ZAMÓW PRZEZ... UŻYWAJĄC
ma sens w kilku przypadkach:
- Kolejność jest tak rzadka, że
jakaśfunc
sztuczka nie działa. - Pracujesz z nieprymitywnym typem (takim jak
point
,kółko
lub liczb urojonych) i nie chcesz powtarzać się w swoich zapytaniach z dziwnymi obliczeniami. - Zbiór danych, który chcesz posortować, jest tak duży, że wsparcie przez indeks jest pożądane, a nawet wymagane.
Skoncentruję się na złożonych typach danych:często istnieje więcej niż jeden sposób ich rozsądnego sortowania. Dobrym przykładem jest point
:Możesz „uporządkować” je według odległości do (0,0) lub według x najpierw, potem przez y lub po prostu przez y lub cokolwiek innego, co chcesz.
Oczywiście PostgreSQL ma predefiniowane operatory dla punktu
:
> CREATE TABLE p ( p point );
> SELECT p <-> point(0,0) FROM p;
Ale żadne z nich jest zadeklarowana do użycia dla ORDER BY
domyślnie (patrz wyżej):
> 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.
Proste operatory dla punktu
to operatory „poniżej” i „powyżej” <^
i >^
. Porównują po prostu y
część punktu. Ale:
> 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.
ZAMÓW PRZY UŻYCIU
wymaga operatora ze zdefiniowaną semantyką:Oczywiście musi to być operator binarny, musi akceptować ten sam typ co argumenty i musi zwracać wartość logiczną. Myślę, że musi być również przechodnia (jeśli a btree -indeks porządkowania. To wyjaśnia dziwne komunikaty o błędach zawierające odniesienie do btree .
ZAMÓW PRZY UŻYCIU
wymaga również nie tylko jednego operatora do zdefiniowania, ale klasa operatora i rodzina operatorów . Chociaż jeden może zaimplementuj sortowanie za pomocą tylko jednego operatora, PostgreSQL stara się efektywnie sortować i minimalizować porównania. Dlatego używa się kilku operatorów, nawet jeśli określisz tylko jeden – pozostałe muszą być zgodne z pewnymi ograniczeniami matematycznymi – wspomniałem już o przechodniości, ale jest ich więcej.
Przełączanie biegów w górę
Zdefiniujmy coś odpowiedniego:operator punktów, który porównuje tylko y
część.
Pierwszym krokiem jest utworzenie niestandardowej rodziny operatorów, która może być używana przez btree metoda dostępu do indeksu. patrz
> CREATE OPERATOR FAMILY xyzfam USING btree; -- superuser access required!
CREATE OPERATOR FAMILY
Następnie musimy podać funkcję porównawczą, która zwraca -1, 0, +1 przy porównywaniu dwóch punktów. Ta funkcja BĘDZIE nazywać się wewnętrznie!
> CREATE FUNCTION xyz_v_cmp(p1 point, p2 point) RETURNS int
AS $$BEGIN RETURN btfloat8cmp(p1[1],p2[1]); END $$ LANGUAGE plpgsql;
CREATE FUNCTION
Następnie definiujemy klasę operatora dla rodziny. Zapoznaj się z instrukcją obsługi, aby uzyskać objaśnienie liczb.
> 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
Ten krok łączy kilka operatorów i funkcji, a także określa ich związek i znaczenie. Na przykład OPERATOR 1
oznacza:To jest operator dla mniejsze-niż
testy.
Teraz operatory <^
i >^
może być używany w ZAMÓW PRZEZ UŻYCIE
:
> 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 – posortowane według y .
Podsumowując: ZAMÓW PRZEZ... UŻYWAJĄC
to ciekawe spojrzenie pod maską PostgreSQL. Ale niczego nie będziesz potrzebować w najbliższym czasie, chyba że będziesz pracować w bardzo określone obszary technologii baz danych.
Inny przykład można znaleźć w dokumentacji Postgres. z kodem źródłowym dla przykładu tutaj i tutaj. Ten przykład pokazuje również, jak tworzyć operatory.