Contoh yang sangat sederhana adalah:
> SELECT * FROM tab ORDER BY col USING <
Tapi ini membosankan, karena ini bukan apa-apa yang tidak bisa Anda dapatkan dengan ORDER BY col ASC
tradisional .
Juga katalog standar tidak menyebutkan sesuatu yang menarik tentang fungsi/operator perbandingan yang aneh. Anda bisa mendapatkan daftarnya:
> 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);
Anda akan melihat, bahwa sebagian besar ada <
dan >
fungsi untuk tipe primitif seperti integer
, date
dll dan beberapa lagi untuk array dan vektor dan sebagainya. Tak satu pun dari operator ini akan membantu Anda mendapatkan pesanan khusus.
Di sebagian besar kasus di mana pemesanan khusus diperlukan, Anda dapat menggunakan sesuatu seperti ... ORDER BY somefunc(tablecolumn) ...
di mana somefunc
memetakan nilai-nilai dengan tepat. Karena itu bekerja dengan setiap database, ini juga merupakan cara yang paling umum. Untuk hal-hal sederhana, Anda bahkan dapat menulis ekspresi alih-alih fungsi khusus.
Mengganti persneling
ORDER BY ... USING
masuk akal dalam beberapa kasus:
- Pengurutannya sangat jarang, sehingga
somefunc
trik tidak berhasil. - Anda bekerja dengan tipe non-primitif (seperti
point
,circle
atau angka imajiner) dan Anda tidak ingin mengulangi pertanyaan Anda dengan perhitungan yang aneh. - Dataset yang ingin Anda urutkan sangat besar, sehingga dukungan indeks diinginkan atau bahkan diperlukan.
Saya akan fokus pada tipe data yang kompleks:seringkali ada lebih dari satu cara untuk mengurutkannya dengan cara yang masuk akal. Contoh yang bagus adalah point
:Anda dapat "memesan" mereka berdasarkan jarak (0,0), atau dengan x pertama, lalu dengan y atau hanya dengan y atau apa pun yang Anda inginkan.
Tentu saja, PostgreSQL memiliki operator yang telah ditentukan untuk point
:
> CREATE TABLE p ( p point );
> SELECT p <-> point(0,0) FROM p;
Tapi tidak ada dari mereka dinyatakan dapat digunakan untuk ORDER BY
secara default (lihat di atas):
> 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.
Operator sederhana untuk point
adalah operator "di bawah" dan "di atas" <^
dan >^
. Mereka hanya membandingkan y
bagian dari intinya. Tapi:
> 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
membutuhkan operator dengan semantik yang ditentukan:Jelas itu harus menjadi operator biner, ia harus menerima tipe yang sama dengan argumen dan harus mengembalikan boolean. Saya pikir itu juga harus transitif (jika a btree yang tepat -pengurutan indeks. Ini menjelaskan pesan kesalahan aneh yang berisi referensi ke btree .
ORDER BY USING
juga tidak hanya membutuhkan satu operator untuk didefinisikan tetapi kelas operator dan keluarga operator . Sementara satu bisa mengimplementasikan penyortiran hanya dengan satu operator, PostgreSQL mencoba mengurutkan secara efisien dan meminimalkan perbandingan. Oleh karena itu, beberapa operator digunakan bahkan ketika Anda hanya menentukan satu - yang lain harus mematuhi batasan matematika tertentu - Saya telah menyebutkan transitivitas, tetapi ada lebih banyak lagi.
Mengganti Gear
Mari kita definisikan sesuatu yang cocok:Operator untuk titik yang hanya membandingkan y
bagian.
Langkah pertama adalah membuat keluarga operator khusus yang dapat digunakan oleh btree metode akses indeks. lihat
> CREATE OPERATOR FAMILY xyzfam USING btree; -- superuser access required!
CREATE OPERATOR FAMILY
Selanjutnya kita harus menyediakan fungsi pembanding yang mengembalikan -1, 0, +1 saat membandingkan dua titik. Fungsi ini AKAN dipanggil secara internal!
> CREATE FUNCTION xyz_v_cmp(p1 point, p2 point) RETURNS int
AS $$BEGIN RETURN btfloat8cmp(p1[1],p2[1]); END $$ LANGUAGE plpgsql;
CREATE FUNCTION
Selanjutnya kita mendefinisikan kelas operator untuk keluarga. Lihat manual untuk penjelasan angka.
> 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
Langkah ini menggabungkan beberapa operator dan fungsi dan juga mendefinisikan hubungan dan maknanya. Misalnya OPERATOR 1
artinya:Ini adalah operator untuk less-than
tes.
Sekarang operator <^
dan >^
dapat digunakan dalam 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 - diurutkan berdasarkan y .
Singkatnya: ORDER BY ... USING
adalah tampilan yang menarik di bawah kap PostgreSQL. Tapi tidak ada yang Anda perlukan dalam waktu dekat kecuali Anda bekerja sangat bidang tertentu dari teknologi basis data.
Contoh lain dapat ditemukan di dokumen Postgres. dengan kode sumber untuk contoh di sini dan di sini. Contoh ini juga menunjukkan cara membuat operator.