PostgreSQL
 sql >> Teknologi Basis Data >  >> RDS >> PostgreSQL

ORDER BY ... MENGGUNAKAN klausa di PostgreSQL

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.



  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Statistik cakupan kode

  2. Basis Data PostgreSQL Saya Kehabisan Ruang Disk

  3. Laravel:Kesalahan [PDOException]:Tidak Dapat Menemukan Driver di PostgreSQL

  4. Menyortir elemen array

  5. Fitur PostgreSQL Enterprise Baru dan Berkembang dengan Rilis Terbaru