2011-08-26 22 views
33

आदेश BY खंड में खंड के रूप में PostgreSQLdocumentation में वर्णित किया जाता है? क्या परिणामपत्र का वैकल्पिक क्रम प्राप्त करना संभव है?"आदेश द्वारा ... का उपयोग" PostgreSQL

+0

आप "बारी आदेश" से क्या मतलब है? –

उत्तर

37

एक की अनिवार्य विशेषता है:

> 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) के लिए "आदेश" दूरी के अनुसार उन्हें, या एक्स पहले, तो 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 परिभाषित अर्थ विज्ञान के साथ एक ऑपरेटर की आवश्यकता है: जाहिर है यह एक द्विआधारी ऑपरेटर होना चाहिए, यह तर्क के रूप में एक ही प्रकार को स्वीकार करना चाहिए और यह बूलियन लौट जाना चाहिए। मुझे लगता है कि यह भी संक्रमणीय होना चाहिए (यदि < बी और बी < सी तो < सी) होना चाहिए। और आवश्यकताएं हो सकती हैं। लेकिन इन सभी आवश्यकताओं को उचित btree -index ऑर्डरिंग के लिए भी आवश्यक है। यह btree के संदर्भ वाले अजीब त्रुटि संदेशों को बताता है।

ORDER BY USING भी जरूरी है सिर्फ एक ऑपरेटर में परिभाषित किया जा करने के लिए नहीं है, लेकिन एक ऑपरेटर वर्ग और एक ऑपरेटर परिवार। जबकि एक केवल एक ऑपरेटर के साथ सॉर्टिंग लागू कर सकता है, PostgreSQL कुशलतापूर्वक क्रमबद्ध करने और तुलना को कम करने की कोशिश करता है। इसलिए, कई ऑपरेटरों का उपयोग तब भी किया जाता है जब आप केवल एक निर्दिष्ट करते हैं - दूसरों को कुछ गणितीय बाधाओं का पालन करना होगा - मैंने पहले से ही पारगमन का उल्लेख किया है, लेकिन और भी कुछ हैं। जो केवल y हिस्सा तुलना अंक के लिए एक ऑपरेटर:

स्विचिंग अप

गियर्स के उपयुक्त कुछ को परिभाषित करते हैं।

पहला कदम कस्टम ऑपरेटर परिवार बनाना है जिसका उपयोग btree अनुक्रमणिका एक्सेस विधि द्वारा किया जा सकता है। see

> 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 

अगला हम परिवार के लिए ऑपरेटर वर्ग को परिभाषित करते हैं। संख्याओं की व्याख्या के लिए See the manual

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

देखा - y के अनुसार क्रमबद्ध।

इसे समेटने के लिए:ORDER BY ... USING PostgreSQL के हुड के नीचे एक दिलचस्प रूप है। लेकिन जब तक आप बहुत डेटाबेस तकनीक के विशिष्ट क्षेत्रों में काम नहीं करते हैं, तब तक आपको कुछ भी आवश्यकता नहीं होगी।

उदाहरण के लिए in the Postgres docs.here और here के लिए स्रोत कोड के साथ एक और उदाहरण पाया जा सकता है। यह उदाहरण यह भी दिखाता है कि ऑपरेटरों को कैसे बनाया जाए।

+1

+1 ग्रेट उत्तर! –

+0

बहुत बहुत अच्छी व्याख्या, धन्यवाद। – 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

यह इस मुझे लगता है कि जैसे कुछ लग सकता है (मैं अब इस अधिकार को सत्यापित करने के postgres नहीं है, लेकिन बाद में सत्यापित करेंगे)

SELECT Name FROM Person 
ORDER BY NameId USING > 
+0

आपके द्वारा छोड़ी गई रेखा भी दिलचस्प है: '(लेकिन उपयोगकर्ता द्वारा परिभाषित डेटा प्रकार का निर्माता डिफ़ॉल्ट सॉर्ट ऑर्डरिंग को ठीक से परिभाषित कर सकता है, और यह अन्य नामों के साथ ऑपरेटरों के अनुरूप हो सकता है।)' – Vache

+0

मुझे लगता है कि ओपी पहले से ही है यह जानता है; वे उपयोग उदाहरणों के लिए पूछ रहे हैं – NullUserException

+0

मैंने पहले से ही इसे पढ़ा है, लेकिन क्या आप "उपयोग <" और "उपयोग>" से अन्य उदाहरण दे सकते हैं? – markus

4

नमूने:

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 

तो, यह desc और asc के बराबर है। लेकिन आप अपने खुद के ऑपरेटर का उपयोग कर सकते हैं, कि बहुत ही सरल उदाहरण होगा USING

+1

क्या आप मुझे कस्टम ऑपरेटर का उपयोग करके एक उदाहरण दे सकते हैं? – markus

+2

मैं इसके बारे में भी उत्सुक हूं।यह पोस्टग्रेस की काफी निफ्टी फीचर की तरह लगता है, वहां –

+0

ठीक है, सरल 'फ़ंक्शन op_func बनाएं ...' => 'ऑपरेटर बनाएं === (प्रक्रिया = op_func' =>' ऑर्डर द्वारा === 'मुझे फेंक दिया 'त्रुटि : ऑपरेटर === मान्य ऑर्डरिंग ऑपरेटर नहीं है लाइन 1: परीक्षण क्रम से = === ^ एचआईएनटी: ऑर्डर ऑपरेटरों को बीटीआर ऑपरेटर परिवारों के सदस्य "<" or ">" होना चाहिए। ऑपरेटर कक्षाओं और परिवारों से काफी परिचित है, इसलिए अभी तक उदाहरण के साथ नहीं आ सकता है। मैं इसकी जांच करूंगा, लेकिन मैं वास्तव में कोई पोस्टग्रेएसक्यूएल गुरु नहीं हूं ... – J0HN

1

अच्छा जवाब, लेकिन उन्होंने उपयोग करने के लिए एक वास्तविक मूल्यवान मामला नहीं बताया।

जब आप गैर डिफ़ॉल्ट ऑपरेटरों परिवार के साथ सूचकांक बनाने, उदाहरण के varchar_pattern_ops के लिए (~> ~, ~ < ~, ~> = ~ ...) < के बजाय,>,> = ... तो अगर आप आधार पर खोज इंडेक्स पर और आप क्लॉज द्वारा क्रम में इंडेक्स का उपयोग करना चाहते हैं, आपको उचित ऑपरेटर के साथ उपयोग करने की आवश्यकता है।

इस तरह के उदाहरण में दिखाया जा सकता है:

CREATE INDEX index_words_word ON words(word text_pattern_ops); 

चलें इस दो प्रश्नों की तुलना:

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

और

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

उनकी फांसी के बीच अंतर पर लगभग 100 गुना है 500 के शब्द डीबी! और नॉन-सी लोकेल के भीतर भी परिणाम सही नहीं हो सकते हैं।

यह कैसे खुश हो सकता है?

जब आप की तरह के साथ खोज और आदेश BY खंड बनाने, आप वास्तव में यह कॉल करने के:

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

आपका सूचकांक के साथ ~ < ~ मन में ऑपरेटर बनाया है, तो पीजी द्वारा दिए गए आदेश में दिए गए इंडेक्स उपयोग नहीं कर सकते खंड। बातें किया पाने के लिए सही क्वेरी इस फार्म को फिर से लिखा जाना चाहिए:

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

या

SELECT * FROM words WHERE word LIKE 'o%' ORDER BY word USING ~<~ LIMIT 10; 
संबंधित मुद्दे