रेल जहां हालत नहीं NIL का उपयोग कर


359

रेल 3 शैली का उपयोग करके मैं इसके विपरीत कैसे लिखूंगा:

Foo.includes(:bar).where(:bars=>{:id=>nil})

मैं खोजना चाहता हूं कि आईडी शून्य नहीं है। मैंने कोशिश की:

Foo.includes(:bar).where(:bars=>{:id=>!nil}).to_sql

लेकिन वह रिटर्न:

=> "SELECT     \"foos\".* FROM       \"foos\"  WHERE  (\"bars\".\"id\" = 1)"

यह निश्चित रूप से नहीं है कि मुझे क्या चाहिए, और लगभग एआरएल में एक बग की तरह लगता है।


2
!niltrueरूबी में मूल्यांकन करता है, और एआरएल एक SQL क्वेरी में अनुवाद trueकरता 1है। तो उत्पन्न क्वेरी वास्तव में है जो आपने पूछा था - यह एक एआरएल बग नहीं था।
युवल

जवाबों:


510

रेल 3 के साथ ऐसा करने का विहित तरीका:

Foo.includes(:bar).where("bars.id IS NOT NULL")

ActiveRecord 4.0 और इसके बाद के संस्करण where.notआप ऐसा कर सकते हैं:

Foo.includes(:bar).where.not('bars.id' => nil)
Foo.includes(:bar).where.not(bars: { id: nil })

तालिकाओं के बीच स्कोप के साथ काम करते समय, मैं लाभ उठाना पसंद mergeकरता हूं ताकि मैं मौजूदा स्कोप का अधिक आसानी से उपयोग कर सकूं।

Foo.includes(:bar).merge(Bar.where.not(id: nil))

इसके अलावा, चूंकि includesहमेशा एक सम्मिलित रणनीति नहीं चुनते हैं, इसलिए आपको referencesयहां भी उपयोग करना चाहिए , अन्यथा आप अवैध एसक्यूएल के साथ समाप्त हो सकते हैं।

Foo.includes(:bar)
   .references(:bar)
   .merge(Bar.where.not(id: nil))

1
पिछले एक यहाँ मेरे लिए काम नहीं कर रहा है, क्या हमें इसके लिए एक अतिरिक्त रत्न या प्लगइन की आवश्यकता है? मुझे मिलता है: rails undefined method 'not_eq' for :confirmed_at:Symbol..
टिम बास

3
@ समय हाँ, मेटावेयर रत्न मैं ऊपर जुड़ा हुआ है।
एडम लाससेक

3
मुझे वह उपाय पसंद है जिसके लिए अन्य रत्नों की आवश्यकता नहीं है :) भले ही वह थोड़ा बदसूरत हो
अयस्क २६'११

1
@oreoshake मेटावेयर / स्क्वील अच्छी तरह से लायक हैं, यह सिर्फ एक छोटा पहलू है। लेकिन निश्चित रूप से एक सामान्य मामला जानना अच्छा है।
एडम लाससेक

1
@BKSpurgeon चेनिंग की whereस्थिति बस एक एएसटी का निर्माण कर रही है, यह डेटाबेस को तब तक नहीं मारता है जब तक कि आप टर्मिनल विधि को हिट नहीं करते हैं जैसे eachया to_a। क्वेरी का निर्माण प्रदर्शन की चिंता नहीं है; आप डेटाबेस से क्या अनुरोध कर रहे हैं।
एडम लाससेक

251

यह एआरल में बग नहीं है, यह आपके तर्क में एक बग है।

आप यहाँ क्या चाहते हैं:

Foo.includes(:bar).where(Bar.arel_table[:id].not_eq(nil))

2
मैं उत्सुक हूँ कि फिर क्या मोड़ है! '1' में शून्य करने के लिए
SooDesuNe

12
एक अनुमान के अनुसार, नील रिटर्न true, जो एक बूलियन है। :id => trueआप id = 1SQLese में हो जाता है ।
जेटी

कच्चे sql अंश लिखने से बचने का यह एक अच्छा तरीका है। वाक्य-विन्यास हालांकि स्क्वील के रूप में संक्षिप्त नहीं है।
केल्विन

1
मैं sqlite3 के साथ ऐसा करने में कामयाब नहीं हुआ। sqlite3 देखना चाहता है field_name != 'NULL'
mjnissim

@ जेटेटिक जब तक आप पोस्टग्रैज का उपयोग नहीं कर रहे हैं, जिस स्थिति में आपको id = 't':)
akingoftruth

36

रेल 4 के लिए:

तो, जो आप चाहते हैं वह एक आंतरिक जुड़ाव है, इसलिए आपको वास्तव में केवल विधेय का उपयोग करना चाहिए:

  Foo.joins(:bar)

  Select * from Foo Inner Join Bars ...

लेकिन, रिकॉर्ड के लिए, यदि आप "NOT NULL" शर्त चाहते हैं तो बस विधेय का उपयोग न करें:

Foo.includes(:bar).where.not(bars: {id: nil})

Select * from Foo Left Outer Join Bars on .. WHERE bars.id IS NOT NULL

ध्यान दें कि यह सिंटैक्स एक अवक्षेपण की रिपोर्ट करता है (यह एक स्ट्रिंग SQL स्निपेट के बारे में बात करता है, लेकिन मुझे लगता है कि हैश की स्थिति को पार्सर में स्ट्रिंग में बदल दिया गया है?), इसलिए अंत में संदर्भ जोड़ना सुनिश्चित करें:

Foo.includes(:bar).where.not(bars: {id: nil}).references(:bar)

चेतावनी चेतावनी: ऐसा लगता है कि आप उत्सुक लोडिंग टेबल (एस: (....) में से एक हैं) जो एक स्ट्रिंग SQL स्निपेट में संदर्भित हैं। उदाहरण के लिए:

Post.includes(:comments).where("comments.title = 'foo'")

वर्तमान में, सक्रिय रिकॉर्ड तालिका को स्ट्रिंग में पहचानता है, और एक अलग क्वेरी में टिप्पणियों को लोड करने के बजाय क्वेरी तालिका में शामिल करना जानता है। हालाँकि, एक पूर्ण विकसित SQL पार्सर लिखे बिना ऐसा करना स्वाभाविक रूप से त्रुटिपूर्ण है। चूँकि हम SQL पार्सर लिखना नहीं चाहते हैं, हम इस कार्यक्षमता को हटा रहे हैं। अब से, आपको स्पष्ट रूप से सक्रिय रिकॉर्ड बताना होगा जब आप किसी स्ट्रिंग से तालिका संदर्भित कर रहे हैं:

Post.includes(:comments).where("comments.title = 'foo'").references(:comments)

1
referencesकॉल मुझे मदद की!
दिबांग


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