2011-08-26 24 views
33

Mệnh đề ORDER BY được mô tả trong các PostgreSQLdocumentation như:"ORDER BY ... SỬ DỤNG" điều khoản trong PostgreSQL

ORDER BY expression [ ASC | DESC | USING operator ] [ NULLS { FIRST | LAST } ] [, ...] 

Ai đó có thể cho tôi một số ví dụ về cách sử dụng USING operator? Có thể nhận được thứ tự xen kẽ của resultset không?

+0

Ý anh là gì bởi "trật tự xen kẽ"? –

Trả lời

37

Một ví dụ rất đơn giản sẽ là:

> SELECT * FROM tab ORDER BY col USING < 

Nhưng đây là nhàm chán, bởi vì đây là không có gì bạn không thể có được với truyền thống ORDER BY col ASC .

Danh mục tiêu chuẩn cũng không đề cập đến bất kỳ điều gì thú vị về các toán tử/toán tử so sánh lạ. Bạn có thể nhận được một danh sách trong số họ:

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

Bạn sẽ nhận thấy rằng có phần lớn là <> chức năng với nhiều loại nguyên thủy như integer, date vv và một số chi tiết cho các mảng và vectơ và vân vân. Không một nhà khai thác nào trong số này sẽ giúp bạn có được một đơn đặt hàng tùy chỉnh.

Trong hầu hết trường hợp yêu cầu đặt hàng tùy chỉnh, bạn có thể lấy đi bằng cách sử dụng một cái gì đó như ... ORDER BY somefunc(tablecolumn) ... nơi ánh xạ giá trị một cách thích hợp. Bởi vì điều đó làm việc với mọi cơ sở dữ liệu, đây cũng là cách phổ biến nhất. Đối với những điều đơn giản, bạn thậm chí có thể viết một biểu thức thay vì một chức năng tùy chỉnh.

bánh răng Switching lên

ORDER BY ... USING có ý nghĩa trong một số trường hợp:

  • Trật tự là rất phổ biến, đó là lừa somefunc không hoạt động.
  • Bạn làm việc với loại không nguyên thủy (như point, circle hoặc số ảo) và bạn không muốn lặp lại chính mình trong các truy vấn của mình với các phép tính lạ.
  • Tập dữ liệu bạn muốn sắp xếp quá lớn, hỗ trợ bởi chỉ mục là mong muốn hoặc thậm chí được yêu cầu.

Tôi sẽ tập trung vào các kiểu dữ liệu phức tạp: thường có nhiều cách để sắp xếp chúng theo cách hợp lý.Ví dụ tốt là point: Bạn có thể "đặt hàng" chúng theo khoảng cách tới (0,0) hoặc trước tiên là x, sau đó là y hoặc chỉ bằng y hoặc bất kỳ thứ gì bạn muốn.

Tất nhiên, PostgreSQL khai thác được xác định trước cho point:

> CREATE TABLE p (p point); 
    > SELECT p <-> point(0,0) FROM p; 

Nhưng none trong số họ bị tuyên bố có thể sử dụng cho ORDER BY theo mặc định (xem ở trên):

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

khai thác đơn giản cho point là các toán tử "bên dưới" và "ở trên" <^>^. Họ so sánh chỉ đơn giản là phần y của điểm. Nhưng:

> 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 đòi hỏi một nhà điều hành với ngữ nghĩa được định nghĩa: Rõ ràng nó phải là một nhà điều hành nhị phân, nó phải chấp nhận cùng loại như các đối số và nó phải trả lại boolean. Tôi nghĩ rằng nó cũng phải là transitive (nếu là < b và b < c thì một số < c). Có thể có nhiều yêu cầu hơn. Nhưng tất cả các yêu cầu này cũng cần thiết cho việc đặt hàng btree -index phù hợp. Điều này giải thích các thông báo lỗi lạ có chứa tham chiếu đến btree.

ORDER BY USING cũng đòi hỏi không chỉ một nhà điều hành phải được xác định nhưng một lớp hành và một gia đình hành. Trong khi một có thể thực hiện sắp xếp chỉ với một toán tử, PostgreSQL cố sắp xếp một cách hiệu quả và giảm thiểu các so sánh. Do đó, một số toán tử được sử dụng ngay cả khi bạn chỉ định một - các toán tử khác phải tuân thủ một số ràng buộc toán học nhất định - tôi đã đề cập đến sự chuyển đổi, nhưng có nhiều hơn.

Gears Switching lên

Hãy xác định một cái gì đó phù hợp: Một nhà điều hành cho điểm mà so sánh chỉ là phần y.

Bước đầu tiên là tạo gia đình nhà điều hành tùy chỉnh có thể được sử dụng theo phương pháp truy cập chỉ mục btree chỉ mục. see

> CREATE OPERATOR FAMILY xyzfam USING btree; -- superuser access required! 
    CREATE OPERATOR FAMILY 

Tiếp theo, chúng tôi phải cung cấp hàm so sánh trả về -1, 0, +1 khi so sánh hai điểm. Chức năng này S 01N được gọi nội bộ!

> CREATE FUNCTION xyz_v_cmp(p1 point, p2 point) RETURNS int 
     AS $$BEGIN RETURN btfloat8cmp(p1[1],p2[1]); END $$ LANGUAGE plpgsql; 
    CREATE FUNCTION 

Tiếp theo, chúng tôi xác định lớp toán tử cho gia đình. See the manual để giải thích về các con số.

> 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 

Bước này kết hợp một số toán tử và chức năng và cũng xác định mối quan hệ và ý nghĩa của chúng. Ví dụ: OPERATOR 1 có nghĩa là: Đây là toán tử cho các thử nghiệm less-than.

Bây giờ các nhà khai thác <^ và '> ^' có thể được sử dụng trong 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 - sắp xếp theo y.

Để tổng hợp:ORDER BY ... USING là một giao diện thú vị dưới mui xe của PostgreSQL. Nhưng không có gì bạn sẽ yêu cầu bất cứ lúc nào sớm trừ khi bạn làm việc trong rất các lĩnh vực cụ thể của công nghệ cơ sở dữ liệu.

Ví dụ khác có thể được tìm thấy in the Postgres docs. với mã nguồn cho ví dụ herehere. Ví dụ này cũng cho thấy cách tạo các toán tử.

+1

+1 Câu trả lời tuyệt vời! –

+0

Giải thích rất tốt, cảm ơn bạn. – LauriK

0

Optionally one can add the key word ASC (ascending) or DESC (descending) after any expression in the ORDER BY clause. If not specified, ASC is assumed by default. Alternatively, a specific ordering operator name can be specified in the USING clause. An ordering operator must be a less-than or greater-than member of some B-tree operator family. ASC is usually equivalent to USING < and DESC is usually equivalent to USING >.

PostgreSQL 9.0

Nó có thể giống như thế này tôi nghĩ (tôi không có postgres để xác minh này ngay bây giờ, nhưng sẽ kiểm tra sau)

SELECT Name FROM Person 
ORDER BY NameId USING > 
+0

Dòng bạn bỏ ra cũng thú vị: '(Nhưng tác giả của kiểu dữ liệu do người dùng định nghĩa có thể xác định chính xác thứ tự sắp xếp mặc định là gì và nó có thể tương ứng với toán tử với tên khác.)' – Vache

+0

Tôi nghĩ rằng OP đã biết điều này; họ đang yêu cầu các ví dụ sử dụng – NullUserException

+0

Tôi đã đọc điều đó, nhưng bạn có thể đưa ra các ví dụ khác hơn là "sử dụng <" và "sử dụng>" không? – markus

4

Samples:

CREATE TABLE test 
(
    id serial NOT NULL, 
    "number" integer, 
    CONSTRAINT test_pkey PRIMARY KEY (id) 
) 

insert into test("number") values (1),(2),(3),(0),(-1); 

select * from test order by number USING > //gives 3=>2=>1=>0=>-1 

select * from test order by number USING < //gives -1=>0=>1=>2=>3 

Vì vậy, nó tương đương với descasc. Nhưng bạn có thể sử dụng toán tử của riêng mình, đó là tính năng thiết yếu của USING

+1

Bạn có thể cho tôi một ví dụ bằng cách sử dụng toán tử tùy chỉnh không? – markus

+2

Tôi cũng tò mò về điều đó.Điều đó nghe có vẻ giống như một tính năng khá tiện lợi của Postgres, có –

+0

Vâng, đơn giản 'Tạo hàm op_func ...' => 'Tạo toán tử === (procedure = op_func' =>' order by === 'ném tôi' ERROR : toán tử === không phải là toán tử sắp xếp hợp lệ Dòng 1: chọn * từ thứ tự kiểm tra theo số USING === ^ GỢI Ý: Toán tử đặt hàng phải là "<" or ">" thành viên của gia đình điều hành btree.'. khá quen thuộc với các nhà điều hành lớp và gia đình, vì vậy không thể đưa ra ví dụ được nêu ra.Tôi sẽ điều tra nó, nhưng tôi không có guru PostgreSQL thực sự ... – J0HN

1

Câu trả lời hay, nhưng họ không đề cập đến một trường hợp có giá trị thực sự cho SỬ DỤNG.

Khi bạn tạo chỉ mục với nhóm toán tử không mặc định, ví dụ: varchar_pattern_ops (~> ~, ~ < ~, ~> = ~ ...) thay vì <,>,> = ... thì nếu bạn tìm kiếm dựa trên trên chỉ mục và bạn muốn sử dụng chỉ mục theo thứ tự theo mệnh đề bạn cần chỉ định USING với toán tử thích hợp.

này có thể được minh họa bằng những ví dụ:

CREATE INDEX index_words_word ON words(word text_pattern_ops); 

Cho phép so sánh này hai truy vấn:

SELECT * FROM words WHERE word LIKE 'o%' LIMIT 10; 

SELECT * FROM words WHERE word LIKE 'o%' ORDER BY word LIMIT 10; 

Sự khác biệt giữa hành của họ là gần 100 lần tại 500K từ DB! Và các kết quả có thể không chính xác trong miền địa phương không phải C.

Làm thế nào điều này có thể xảy ra?

Khi bạn làm cho tìm kiếm với LIKE và mệnh đề ORDER BY, bạn thực sự thực hiện cuộc gọi này:

SELECT * FROM words WHERE word ~>=~ 'o' AND word ~<~'p' ORDER BY word USING < LIMIT 10; 

index của bạn tạo ra với ~ < ~ điều hành trong tâm trí, vì vậy PG không thể sử dụng chỉ số được đưa ra trong một thứ tự nhất định BẰNG mệnh đề. Để hoàn thành mọi việc truy vấn đúng phải được viết lại để hình thức này:

SELECT * FROM words WHERE word ~>=~ 'o' AND word ~<~'p' ORDER BY word USING ~<~ LIMIT 10; 

hoặc

SELECT * FROM words WHERE word LIKE 'o%' ORDER BY word USING ~<~ LIMIT 10; 
Các vấn đề liên quan