कैसे और के बजाय या के साथ प्रश्नों की गुंजाइश है?


137

मैं Rails3, ActiveRecord का उपयोग कर रहा हूं

बस सोच रहा था कि मैं कैसे और के बजाय या बयान के साथ scopes श्रृंखला कर सकते हैं।

जैसे

Person.where(:name => "John").where(:lastname => "Smith")

वह आम तौर पर रिटर्न:

name = 'John' AND lastname = 'Smith'

लेकिन मैं चाहूंगा:

`name = 'John' OR lastname = 'Smith'

जवाबों:


107

तुम करोगे

Person.where('name=? OR lastname=?', 'John', 'Smith')

अभी, नए AR3 सिंटैक्स द्वारा कोई अन्य या समर्थन नहीं है (जो कि कुछ 3 पार्टी मणि का उपयोग किए बिना है)।


21
और सिर्फ सुरक्षा के लिए, यह व्यक्ति के रूप में व्यक्त करने के लायक है। "(" नाम =? या अंतिम नाम =? ", 'जॉन', 'स्मिथ')
कैम्ब्रिज

6
यह अभी भी रेल 4 में लागू है? रेल 4 में कुछ भी बेहतर नहीं हुआ?
डोनैटो

11
रेल 4 में कोई बदलाव नहीं, लेकिन रेल 5 में .orनिर्मित होगी
चूना

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

2
रेल 5 के साथ, आप कुछ ऐसा भी कर सकते हैं, Person.where ("name = 'John'") या (Person.where ("lastname = 'Smith'"))
shyam

59

इस पुल अनुरोध के अनुसार , रेल 5 अब प्रश्नों का पीछा करने के लिए निम्नलिखित सिंटैक्स का समर्थन करती है:

Post.where(id: 1).or(Post.where(id: 2))

इस मणि के माध्यम से रेल 4.2 में कार्यक्षमता का एक बैकपोर्ट भी है


48

ARel का प्रयोग करें

t = Person.arel_table

results = Person.where(
  t[:name].eq("John").
  or(t[:lastname].eq("Smith"))
)

1
क्या कोई इस पर टिप्पणी कर सकता है कि क्या पोस्टग्रेज में इस प्रकार की क्वेरी टूटती है?
ओलिवियर लैकन

ARel को DB-agnostic माना जाता है।
साइमन पेरेपेलिट्स

हालांकि यह एक अच्छा विचार है, ARel एक सार्वजनिक API नहीं है और इसका उपयोग करने से आपका ऐप अनपेक्षित तरीके से टूट सकता है, इसलिए मैं इसके खिलाफ सलाह दूंगा जब तक कि आप ARel API के विकास पर ध्यान न दें।
ओलिवियर लैकन

7
@OlivierLacan Arel एक सार्वजनिक एपीआई है, या अधिक सटीक रूप से, यह एक को उजागर करता है। सक्रिय रिकॉर्ड बस सुविधा के तरीके प्रदान करता है जो इसे हुड के तहत उपयोग करते हैं, यह पूरी तरह से अपने आप पर इसका उपयोग करने के लिए वैध है। यह सिमेंटिक संस्करण का अनुसरण करता है, इसलिए जब तक आप प्रमुख संस्करण (3.xx => 4.xx) नहीं बदल रहे हैं, तब तक ब्रेकिंग परिवर्तन के बारे में चिंता करने की कोई आवश्यकता नहीं है।
ग्रे

41

बस एक ही कॉलम के लिए ऐरे सिंटैक्स पोस्ट करना या बाहर झाँकने में मदद करने के लिए प्रश्न करना।

Person.where(name: ["John", "Steve"])

2
प्रश्न जॉन को नाम और स्मिथ के खिलाफ अंतिम नाम
स्टीवन_नोबल

11
@steven_noble - यही कारण है कि मैंने "उसी कॉलम" को या क्वेरी के साथ बोल्ड किया। मैं टिप्पणी को पूरी तरह से हटा सकता हूं, लेकिन यह सोचा कि यह लोगों के लिए उपयोगी होगा "या" SO प्रश्नों को क्वेरी करें।
daino3

38

रेल 4 के लिए अद्यतन

कोई 3 पार्टी रत्नों की आवश्यकता है

a = Person.where(name: "John") # or any scope 
b = Person.where(lastname: "Smith") # or any scope 
Person.where([a, b].map{|s| s.arel.constraints.reduce(:and) }.reduce(:or))\
  .tap {|sc| sc.bind_values = [a, b].map(&:bind_values) }

पुराना उत्तर

कोई 3 पार्टी रत्नों की आवश्यकता है

Person.where(
    Person.where(:name => "John").where(:lastname => "Smith")
      .where_values.reduce(:or)
)

5
यह वास्तव में संसाधनों और विधि के संदर्भ में ओपी के प्रश्न का एकमात्र शुद्ध उत्तर है। अन्य उत्तरों के लिए या तो (ए) को तृतीय पक्ष एपिस की आवश्यकता होती है या (बी) को orएक पाठ ब्लॉक के भीतर अन्य ऑपरेटरों को प्रक्षेप करने की आवश्यकता होती है , जिनमें से कोई भी ओपी के कोड में परिलक्षित नहीं होता है।
एलनवेल्ली

6
यहाँ एक अच्छा लेख है जो इसे coderwall.com/p/dgv7ag/…
allenwlee

4
प्रयुक्त ...where_values.join(' OR ')मेरे मामले में
सैश

2
.tap {|sc| sc.bind_values = [a, b].map(&:bind_values) }यदि आपके स्कोप्स के पास कोई चर नहीं है, जिसे बाइंडिंग की आवश्यकता हो, तो आप इस हिस्से को छोड़ सकते हैं ।
फतहोकू

22

आप अपने कोड को एसक्यूएल सामान के साथ नहीं मिलाने के लिए मेटावेयर रत्न का उपयोग कर सकते हैं :

Person.where((:name => "John") | (:lastname => "Smith"))

3
+1। मेटावेयर का उत्तराधिकारी एक ही लेखक द्वारा स्क्वील है।
थिलो

22

यदि किसी को इस के लिए एक अद्यतन जवाब की तलाश है, तो ऐसा लगता है कि रेल में इसे पाने के लिए एक मौजूदा पुल अनुरोध है: https://github.com/rails/rails/pull/9052

ActiveRecord के लिए @ j-mcnally's मंकी पैच ( https://gist.github.com/j-mcnally/250eaaceef234dd8971b ) के लिए धन्यवाद आप निम्न कार्य कर सकते हैं:

Person.where(name: 'John').or.where(last_name: 'Smith').all

इससे भी अधिक मूल्यवान है, चेन स्कोप की क्षमता OR:

scope :first_or_last_name, ->(name) { where(name: name.split(' ').first).or.where(last_name: name.split(' ').last) }
scope :parent_last_name, ->(name) { includes(:parents).where(last_name: name) }

फिर आप पहले या अंतिम नाम के साथ सभी व्यक्तियों को या जिनके माता-पिता अंतिम नाम के साथ मिल सकते हैं

Person.first_or_last_name('John Smith').or.parent_last_name('Smith')

इस के उपयोग के लिए सबसे अच्छा उदाहरण नहीं है, लेकिन सिर्फ सवाल के साथ इसे फिट करने की कोशिश कर रहा है।


2
आपको इसके लिए किस संस्करण या रेल की आवश्यकता है?
सैश करें

3
नवीनतम चर्चा और पुल अनुरोध जो इसे रेल कोर में बना देगा, वह यहां पाया जा सकता है: github.com/rails/rails/pull/16052 रेलगाड़ी.or श्रृंखला कार्यक्षमता के आधिकारिक रिलीज के लिए लक्षित है। मैं उन रेल पैच का उपयोग करने में सक्षम था जिसका मैंने रेल्स = = 3.2 पर उल्लेख किया था; हालाँकि, आप अपने कोड में किसी भी लंबे समय तक बदलाव लाने के लिए रेल 5 का इंतजार करना चाहते हैं।
कोडनमेव

1
हां, यह विलय कर दिया गया था और रेल के साथ जारी किया गया था 5.
amoebe

10

मेरे लिए (रेल 4.2.5) यह केवल इस तरह काम करता है:

{ where("name = ? or name = ?", a, b) }

8

यदि आप रेल 3.0+ का उपयोग कर रहे हैं तो यह मेटावेयर के लिए एक अच्छा उम्मीदवार होगा, लेकिन यह रेल 3.1 पर काम नहीं करता है। आप इसके बजाय स्क्वील आज़माना चाह सकते हैं । इसे उसी लेखक ने बनाया है। यहां बताया गया है कि आप OR आधारित श्रृंखला का प्रदर्शन कैसे करेंगे:

Person.where{(name == "John") | (lastname == "Smith")}

आप कई अन्य भयानक चीजों के बीच मिश्रण और / या कर सकते हैं


8

रेल / ActiveRecord का अद्यतन संस्करण इस वाक्यविन्यास को मूल रूप से समर्थन कर सकता है। यह समान दिखाई देगा:

Foo.where(foo: 'bar').or.where(bar: 'bar')

जैसा कि इस पुल अनुरोध में उल्लेख किया गया है https://github.com/rails/rails/pull/9052

अभी के लिए, बस निम्नलिखित कार्यों के साथ चिपके रहना बहुत अच्छा है:

Foo.where('foo= ? OR bar= ?', 'bar', 'bar')


1
Foo.where(foo: 'bar1').or.where(bar: 'bar2')काम नहीं करता। यह Foo.where (foo: 'bar1') होना चाहिए। or.where (Foo.where (बार: 'बार 2'))
Ana María Martínez Gómez

6

रेल 4 + स्कोप + आरेल

class Creature < ActiveRecord::Base
    scope :is_good_pet, -> {
        where(
            arel_table[:is_cat].eq(true)
            .or(arel_table[:is_dog].eq(true))
            .or(arel_table[:eats_children].eq(false))
        )
    }
end

मैंने .or और नो लक के साथ स्कोप्स नाम की कोशिश की, लेकिन यह उन बुलियन सेट के साथ कुछ भी खोजने के लिए काम किया। SQL की तरह उत्पन्न करता है

SELECT 'CREATURES'.* FROM 'CREATURES' WHERE ((('CREATURES'.'is_cat' = 1 OR 'CREATURES'.'is_dog' = 1) OR 'CREATURES'.'eats_children' = 0))


4

यदि आप एक गुंजाइश प्रदान करने की तलाश कर रहे हैं (स्पष्ट रूप से पूरे डेटासेट पर काम करने के बजाय) यहां आपको रेल 5 के साथ क्या करना चाहिए:

scope :john_or_smith, -> { where(name: "John").or(where(lastname: "Smith")) }

या:

def self.john_or_smith
  where(name: "John").or(where(lastname: "Smith"))
end

यह सही है, लेकिन एक ही चीज़ से अधिक शाब्दिक उत्तर है जो stackoverflow.com/a/42894753/1032882 तकनीकी करता है।
रूडीऑनएल्स

3

यदि आप यह नहीं लिख सकते हैं कि "या" कथन को शामिल करने के लिए मैन्युअल रूप से क्लॉज कहां है (यानी, आप दो स्कोप को मिलाना चाहते हैं), तो आप यूनियन का उपयोग कर सकते हैं:

Model.find_by_sql("#{Model.scope1.to_sql} UNION #{Model.scope2.to_sql}")

(स्रोत: ActiveRecord क्वेरी यूनियन )

यह क्वेरी से मेल खाते सभी रिकॉर्ड लौटाएगा। हालाँकि, यह एक एरे लौटाता है, न कि एर्ल। यदि आप वास्तव में एक वापसी चाहते हैं, तो आप इस gist की जाँच करें: https://gist.github.com/j-mcnally/250eaaceef234dd8971b

यह काम करेगा, जब तक कि आप बंदर पैचिंग रेल को बुरा नहीं मानते।


2

इन संबंधित प्रश्नों को भी देखें: यहां , यहां और यहां

इस लेख और इस मूल उत्तर के आधार पर रेल 4 के लिए

Person
  .unscoped # See the caution note below. Maybe you want default scope here, in which case just remove this line.
  .where( # Begin a where clause
    where(:name => "John").where(:lastname => "Smith")  # join the scopes to be OR'd
    .where_values  # get an array of arel where clause conditions based on the chain thus far
    .inject(:or)  # inject the OR operator into the arels 
    # ^^ Inject may not work in Rails3. But this should work instead:
    .joins(" OR ")
    # ^^ Remember to only use .inject or .joins, not both
  )  # Resurface the arels inside the overarching query

नोट अंत में लेख की सावधानी:

रेलगाड़ी 4.1+

केवल एक नियमित स्कोप के रूप में 4.1 रैल डिफ़ॉल्ट_स्क्रीन को मानता है। डिफ़ॉल्ट स्कोप (यदि आपके पास कोई भी हो) शामिल है, जहां result_values ​​परिणाम और इंजेक्शन शामिल हैं: (या) डिफ़ॉल्ट स्कोप और आपके व्हाट्स के बीच जोड़ या बयान देगा। यह बुरी बात है।

इसे हल करने के लिए, आपको बस क्वेरी को अनसैप करने की आवश्यकता है।


1

यह एक बहुत ही सुविधाजनक तरीका है और यह रेल 5 में ठीक काम करता है:

Transaction
  .where(transaction_type: ["Create", "Correspond"])
  .or(
    Transaction.where(
      transaction_type: "Status",
      field: "Status",
      newvalue: ["resolved", "deleted"]
    )
  )
  .or(
    Transaction.where(transaction_type: "Set", field: "Queue")
  )

0

squeelमणि एक अविश्वसनीय रूप से आसान तरीका यह है, प्रदान करता है (@ coloradoblue की विधि की तरह यह कुछ मैं प्रयोग किया जाता से पहले):

names = ["Kroger", "Walmart", "Target", "Aldi"]
matching_stores = Grocery.where{name.like_any(names)}

0

तो मूल प्रश्न का उत्तर, क्या आप 'या' के बजाय 'या' के साथ स्कोप्स में शामिल हो सकते हैं "ऐसा लगता है कि" आप नहीं कर सकते "। लेकिन आप कोड को पूरी तरह से अलग दायरे या क्वेरी को सौंप सकते हैं जो काम करता है, या ActiveRecord जैसे MetaWhere या Squeel से एक अलग फ्रेमवर्क का उपयोग कर सकता है। मेरे मामले में उपयोगी नहीं है

मैं 'pg_search' द्वारा उत्पन्न एक गुंजाइश 'या' कर रहा हूँ, जो कि चयन से थोड़ा अधिक है, इसमें ASC द्वारा आदेश शामिल है, जो एक स्वच्छ संघ की गड़बड़ी करता है। मैं इसे एक हैंडक्राफ्टेड स्कोप के साथ 'या' करना चाहता हूं जो सामान करता है जो मैं pg_search में नहीं कर सकता। इसलिए मुझे इसे इस तरह करना पड़ा है।

Product.find_by_sql("(#{Product.code_starts_with('Tom').to_sql}) union (#{Product.name_starts_with('Tom').to_sql})")

यानी स्कूप्स को sql में बदल देते हैं, हर एक के चारों ओर ब्रैकेट्स लगाते हैं, उन्हें एक साथ जोड़ते हैं और फिर sql उत्पन्न का उपयोग करके find_by_sql करते हैं। यह थोड़ा बकवास है, लेकिन यह काम करता है।

नहीं, मुझे नहीं बताएं कि मैं "खिलाफ: [: नाम,: कोड]" का उपयोग कर सकता हूं। अभी तक। इसलिए नाम से गुंजाइश को हाथ से तैयार किया जाना चाहिए और फिर pg_search गुंजाइश के साथ संघबद्ध किया जाना चाहिए।


-2
names = ["tim", "tom", "bob", "alex"]
sql_string = names.map { |t| "name = '#{t}'" }.join(" OR ")
@people = People.where(sql_string)
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.