रेल: अंतिम नल के साथ आदेश


83

मेरे रेल एप्लिकेशन में मैंने एक मुद्दे को एक दो बार चलाया है जो मैं जानना चाहता हूं कि अन्य लोग कैसे हल करते हैं:

मेरे पास कुछ रिकॉर्ड हैं जहां एक मूल्य वैकल्पिक है, इसलिए कुछ रिकॉर्ड का मूल्य है और कुछ उस कॉलम के लिए अशक्त हैं।

अगर मैं कुछ डेटाबेस पर उस कॉलम द्वारा आदेश देता हूं, तो नल पहले छांटते हैं और कुछ डेटाबेस में नल अंतिम क्रमबद्ध होते हैं।

उदाहरण के लिए, मेरे पास ऐसे फ़ोटो हैं जो किसी संग्रह से संबंधित हो सकते हैं या नहीं भी हो सकते हैं, यानी कुछ फ़ोटो हैं जहाँ collection_id=nilऔर कुछ कहाँ collection_id=1आदि

अगर मैं Photo.order('collection_id desc)SQLite पर करता हूं तो मुझे आखिरी बार नल मिलते हैं लेकिन PostgreSQL पर मुझे सबसे पहले नल मिलते हैं।

क्या इसे संभालने और किसी भी डेटाबेस में लगातार प्रदर्शन प्राप्त करने का एक अच्छा, मानक रेल मार्ग है?

जवाबों:


0

एक साथ सरणियों को जोड़ना आदेश को संरक्षित करेगा:

@nonull = Photo.where("collection_id is not null").order("collection_id desc")
@yesnull = Photo.where("collection_id is null")
@wanted = @nonull+@yesnull

http://www.ruby-doc.org/core/classes/Array.html#M000271


2
खैर, मुझे यह विचार पसंद नहीं है, लेकिन मुझे लगता है कि यह काम करेगा। खेद है कि इसे इतने लंबे समय तक खुला छोड़ दिया गया, मैं उम्मीद कर रहा था कि कुछ अन्य उत्तर दिखाई देंगे। हालांकि, इसके बारे में सोचने में कुछ और समय बिताने के बाद, मुझे लगता है कि इसे फोटो मॉडल पर एक विधि बनाया जा सकता है और फिर यह बहुत बुरा नहीं लगेगा।
एंड्रयू

यदि आप mysql का उपयोग कर रहे हैं तो यह आसान है। मेरा समाधान देखें।
जैकब

सही है, मुझे यह उल्लेख करना चाहिए कि मेरा केवल सबसे अज्ञेय तरीका था जिसे मैं पा सकता था।
एरिक

8
यह एक बुरा विचार है क्योंकि whereकिसी सरणी को वापस नहीं करता है, यह ActiveRecord :: Relation लौटाता है और किसी सरणी में परिणाम को मजबूर करने से वह सब कुछ हो जाएगा जो एक मानक ActiveRecord की अपेक्षा करता है :: Relation to fail (जैसे पृष्ठ पर अंक लगाना)।
माइक बेथानी

1
यह सच है, हालांकि यह उपलब्ध तरीकों को या तो एआर से बाहर निकलता है या पूरी तरह से पोर्टेबल नहीं है।
एरिक

273

मैं SQL में कोई विशेषज्ञ नहीं हूँ, लेकिन क्यों न कुछ छाँटकर अगर कुछ पहले शून्य है, तो आप इसे कैसे छाँटना चाहते हैं।

Photo.order('collection_id IS NULL, collection_id DESC')  # Null's last
Photo.order('collection_id IS NOT NULL, collection_id DESC') # Null's first

यदि आप केवल PostgreSQL का उपयोग कर रहे हैं, तो आप यह भी कर सकते हैं

Photo.order('collection_id DESC NULLS LAST')  #Null's Last
Photo.order('collection_id DESC NULLS FIRST') #Null's First

यदि आप कुछ सार्वभौमिक चाहते हैं (जैसे आप कई डेटाबेस में एक ही क्वेरी का उपयोग कर रहे हैं, तो आप उपयोग कर सकते हैं (@philT के सौजन्य से)

Photo.order('CASE WHEN collection_id IS NULL THEN 1 ELSE 0 END, collection_id')

22
+1, स्वीकृत उत्तर की तुलना में बहुत बेहतर और
m_x

1
वाह, यह एक पुरानी टिप्पणी है! इसलिए मुझे लगता है कि मैं जो कहना चाह रहा था वह था:p = Photo.arel_table; Photo.order(p[:collection_id].eq(nil)).order(p[:collection_id].desc)
m_x

2
ध्यान दें कि NULLS LASTआप .last()अपनी क्वेरी पर नियम 4.2 के रूप में चेन करने की अनुमति नहीं देते हैं । मैंने नीचे एक काम पोस्ट किया है।
लानी बोस

1
IS NULLNULL पंक्तियों को अंतिम रूप देकर ऑर्डर क्यों करता है ? आपको लगता है कि यह उन्हें पहले डाल देगा।
जैकोक्रान

2
@jackocr myguess: IS NULL 1 का मूल्यांकन करता है यदि सच है, तो 0 गलत, हल, 0 से पहले 1 आता है ...
Intentss

37

भले ही अभी 2017 है, लेकिन अभी भी इस बात पर एकमत होना बाकी है कि क्या NULLपूर्वता लेनी चाहिए। आपके द्वारा इसके बारे में स्पष्ट किए बिना, आपके परिणाम DBMS के आधार पर भिन्न हो सकते हैं।

यह मानक निर्दिष्ट नहीं करता है कि गैर-पूर्ण मूल्यों की तुलना में NULL को कैसे आदेश दिया जाना चाहिए, सिवाय इसके कि किसी भी दो NULL को समान रूप से आदेश दिया जाए, और यह कि NULLs सभी गैर-NULL मानों के ऊपर या नीचे क्रमबद्ध करें।

स्रोत, अधिकांश DBMS की तुलना

समस्या का वर्णन करने के लिए, मैंने कुछ सबसे लोकप्रिय मामलों की एक सूची तैयार की, जब यह रेल विकास की बात आती है:

PostgreSQL

NULLउच्चतम मूल्य है।

डिफ़ॉल्ट रूप से, अशक्त मान किसी भी गैर-शून्य मान से बड़े होते हैं।

स्रोत: PostgreSQL प्रलेखन

माई एसक्यूएल

NULLसबसे कम मूल्य है।

जब आप ORDER BY करते हैं, तो NULL मान पहले प्रस्तुत किए जाते हैं यदि आप ORDER BY ... ASC करते हैं और अंतिम यदि आप ORDER BY ... DESC करते हैं।

स्रोत: MySQL प्रलेखन

SQLite

NULLसबसे कम मूल्य है।

एक पूर्ण मान वाली एक पंक्ति आरोही क्रम में नियमित मान वाली पंक्तियों से अधिक है, और यह अवरोही क्रम के लिए उलट है।

स्रोत

उपाय

दुर्भाग्य से, रेल स्वयं इसके लिए कोई समाधान प्रदान नहीं करती है।

PostgreSQL विशिष्ट

PostgreSQL के लिए आप काफी सहजता से उपयोग कर सकते हैं:

Photo.order('collection_id DESC NULLS LAST') # NULLs come last

MySQL विशिष्ट

माईएसक्यूएल के लिए, आप माइनस साइन अपफ्रंट लगा सकते हैं, फिर भी यह सुविधा अनिर्दिष्ट लगती है। न केवल संख्यात्मक मूल्यों के साथ काम करने की अपील करता है, बल्कि तारीखों के साथ भी।

Photo.order('-collection_id DESC') # NULLs come last

PostgreSQL और MySQL विशिष्ट

दोनों को कवर करने के लिए, यह काम करता है:

Photo.order('collection_id IS NULL, collection_id DESC') # NULLs come last

फिर भी, यह SQLite में काम नहीं करता है

सार्वभौमिक समाधान

सभी DBMS के लिए क्रॉस-सपोर्ट प्रदान करने के लिए आपको CASE@PhilIT द्वारा पहले से सुझाई गई क्वेरी का उपयोग करना होगा:

Photo.order('CASE WHEN collection_id IS NULL THEN 1 ELSE 0 END, collection_id')

जो पहले CASEपरिणामों में से प्रत्येक रिकॉर्ड को पहले क्रमबद्ध करने का अनुवाद करता है (डिफ़ॉल्ट आरोही क्रम से, जिसका अर्थ है कि NULLमानों में अंतिम होगा), दूसरा calculation_id


14
Photo.order('collection_id DESC NULLS LAST')

मुझे पता है कि यह एक पुराना है लेकिन मुझे सिर्फ यह स्निपेट मिला और यह मेरे लिए काम करता है।


मुझे नहीं पता कि रूबी / रेल के किस संस्करण में यह काम किया गया था, लेकिन रूबी 2.5 और रेल 5 के लिए काम नहीं करता है।
तस्सो एनेसियादिस

13

कॉलम_नाम के सामने माइनस साइन रखें और ऑर्डर की दिशा उलट दें। यह mysql पर काम करता है। अधिक जानकारी

Product.order('something_date ASC') # NULLS came first
Product.order('-something_date DESC') # NULLS came last

10

शो के लिए देर हो चुकी है लेकिन ऐसा करने के लिए एक सामान्य SQL तरीका है। हमेशा की तरह, CASEबचाव के लिए।

Photo.order('CASE WHEN collection_id IS NULL THEN 1 ELSE 0 END, collection_id')

6

उपयोग करने का सबसे आसान तरीका है:

.order('name nulls first')


3
यह पोस्टग्रैज के लिए सबसे अच्छा है
सर्गई मोस्टोवी

1
यह अच्छा समाधान है, लेकिन सावधान रहें कि ActiveRecord lastएक गलत DESC सम्मिलित करता है।
महावारी

6

पोस्टरिटी की खातिर, मैं एक ActiveRecord त्रुटि से संबंधित को उजागर करना चाहता था NULLS FIRST

यदि आप कॉल करने का प्रयास करते हैं:

Model.scope_with_nulls_first.last

रेल कॉल करने का प्रयास करेगी reverse_order.first, और reverse_orderइसके साथ संगत नहीं है NULLS LAST, क्योंकि यह अमान्य SQL उत्पन्न करने की कोशिश करता है:

PG::SyntaxError: ERROR:  syntax error at or near "DESC"
LINE 1: ...dents"  ORDER BY table_column DESC NULLS LAST DESC LIMIT...

यह कुछ साल पहले कुछ खुले खुले मुद्दों ( एक , दो , तीन ) में संदर्भित किया गया था । मैं निम्नलिखित काम करके इसके आसपास काम करने में सक्षम था:

  scope :nulls_first, -> { order("table_column IS NOT NULL") }
  scope :meaningfully_ordered, -> { nulls_first.order("table_column ASC") }

ऐसा प्रतीत होता है कि दो आदेशों को एक साथ रखने से, वैध एसक्यूएल उत्पन्न होता है:

Model Load (12.0ms)  SELECT  "models".* FROM "models"  ORDER BY table_column IS NULL DESC, table_column ASC LIMIT 1

केवल नकारात्मक पक्ष यह है कि इस दायरे को प्रत्येक दायरे के लिए किया जाना है ।


2

मेरे मामले में मुझे ASC द्वारा शुरू और अंतिम तिथि तक सॉर्ट लाइनों की आवश्यकता थी, लेकिन कुछ मामलों में एंड_डेट शून्य था और यह लाइनें ऊपर होनी चाहिए, मैंने उपयोग किया

@invoice.invoice_lines.order('start_date ASC, end_date ASC NULLS FIRST')


-3

ऐसा लगता है कि आपको रूबी में ऐसा करना होगा यदि आप डेटाबेस प्रकारों के अनुरूप परिणाम चाहते हैं, क्योंकि डेटाबेस स्वयं इस बात की व्याख्या करता है कि NULLS सूची के सामने या अंत में जाता है या नहीं।

Photo.all.sort {|a, b| a.collection_id.to_i <=> b.collection_id.to_i}

लेकिन यह बहुत कुशल नहीं है।

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.