रेल्स: जहाँ एक कथन से अधिक / से कम का उपयोग करना


142

मैं 200 से अधिक आईडी वाले सभी उपयोगकर्ताओं को खोजने की कोशिश कर रहा हूं, लेकिन मुझे विशिष्ट वाक्यविन्यास के साथ कुछ परेशानी हो रही है।

User.where(:id > 200) 

तथा

User.where("? > 200", :id) 

दोनों असफल रहे।

कोई सुझाव?

जवाबों:


276

इसे इस्तेमाल करे

User.where("id > ?", 200) 

1
एर्नी मिलर से
स्क्वील

7
क्या ?इनलाइन करने के बजाय उपयोग करने को प्राथमिकता देना है 200?
davetapley

20
यह स्वचालित रूप से 200 से बच जाता है (क्या उपयोगकर्ता के लिए मूल्य दर्ज करना संभव था, यह एसक्यूएल इंजेक्शन के हमलों की संभावना से बचा जाता है)
user1051849

124

मैंने केवल रेल 4 में इसका परीक्षण किया है, लेकिन whereइस व्यवहार को प्राप्त करने के लिए हैश के साथ एक सीमा का उपयोग करने का एक दिलचस्प तरीका है ।

User.where(id: 201..Float::INFINITY)

SQL उत्पन्न करेगा

SELECT `users`.* FROM `users`  WHERE (`users`.`id` >= 201)

उसी के साथ कम के लिए किया जा सकता है -Float::INFINITY

मैंने एसओ पर तारीखों के साथ ऐसा करने के बारे में पूछते हुए एक समान प्रश्न पोस्ट किया ।

>= बनाम >

लोगों के माध्यम से खुदाई करने और टिप्पणियों की बातचीत का अनुसरण करने से बचने के लिए यहां मुख्य आकर्षण हैं।

ऊपर दी गई विधि केवल एक >=क्वेरी उत्पन्न करती है और ए नहीं> । इस विकल्प को संभालने के कई तरीके हैं।

असतत संख्या के लिए

आप number_you_want + 1ऊपर की तरह एक रणनीति का उपयोग कर सकते हैं जहां मैं उपयोगकर्ताओं के साथ दिलचस्पी रखता हूं id > 200लेकिन वास्तव में तलाश करता हूं id >= 201। यह पूर्णांकों और संख्याओं के लिए ठीक है जहां आप ब्याज की एक इकाई द्वारा वृद्धि कर सकते हैं।

यदि आपके पास एक निरंतर नाम वाले कुएं में निकाली गई संख्या है तो यह एक नज़र में पढ़ने और समझने में सबसे आसान हो सकता है।

उलटा तर्क

हम इस तथ्य का उपयोग कर सकते हैं x > y == !(x <= y)और जहां चेन का उपयोग नहीं करते हैं।

User.where.not(id: -Float::INFINITY..200)

जो SQL उत्पन्न करता है

SELECT `users`.* FROM `users` WHERE (NOT (`users`.`id` <= 200))

यह पढ़ने और तर्क करने के लिए एक अतिरिक्त सेकंड लेता है, लेकिन गैर असतत मूल्यों या स्तंभों के लिए काम करेगा जहां आप + 1रणनीति का उपयोग नहीं कर सकते ।

अरेल की मेज

यदि आप फैंसी प्राप्त करना चाहते हैं तो आप इसका उपयोग कर सकते हैं Arel::Table

User.where(User.arel_table[:id].gt(200))

SQL उत्पन्न करेगा

"SELECT `users`.* FROM `users` WHERE (`users`.`id` > 200)"

विवरण इस प्रकार हैं:

User.arel_table              #=> an Arel::Table instance for the User model / users table
User.arel_table[:id]         #=> an Arel::Attributes::Attribute for the id column
User.arel_table[:id].gt(200) #=> an Arel::Nodes::GreaterThan which can be passed to `where`

यह दृष्टिकोण आपको सटीक एसक्यूएल मिलेगा जिसमें आप रुचि रखते हैं, हालांकि बहुत से लोग सीधे Arel तालिका का उपयोग नहीं करते हैं और इसे गन्दा और / या भ्रमित कर सकते हैं। आपको और आपकी टीम को पता चल जाएगा कि आपके लिए सबसे अच्छा क्या है।

बक्शीश

रेल 5 में शुरू आप तिथियों के साथ भी ऐसा कर सकते हैं!

User.where(created_at: 3.days.ago..DateTime::Infinity.new)

SQL उत्पन्न करेगा

SELECT `users`.* FROM `users` WHERE (`users`.`created_at` >= '2018-07-07 17:00:51')

डबल बोनस

रूबी 2.6 जारी होने के बाद (25 दिसंबर, 2018) आप नई अनंत रेंज सिंटैक्स का उपयोग कर पाएंगे! इसके बजाय 201..Float::INFINITYआप सिर्फ लिखने में सक्षम होंगे 201..इस ब्लॉग पोस्ट में अधिक जानकारी ।


3
जिज्ञासा से बाहर, इस स्वीकृत उत्तर से बेहतर क्यों है?
mecampbellsoup

5
सुपीरियर भ्रामक है। यदि आप स्ट्रिंग्स पर हैश सिंटैक्स का उपयोग करने में सक्षम हैं, तो कई लोग इस एआरएल प्रश्नों के साथ अधिक लचीलापन प्राप्त करते हैं, यही वजह है कि कई इस समाधान को पसंद करेंगे। अपनी परियोजना / टीम / संगठन के आधार पर आप कुछ ऐसा चाहते हैं जो कोड को जानने के लिए किसी व्यक्ति के लिए आसान हो, जो स्वीकृत उत्तर है।
हारून

2
मुझे विश्वास नहीं है कि आप बुनियादी whereमिलान का उपयोग कर सकते हैं । क्योंकि >मैं सुझाव देता हूं कि >= (number_you_want + 1)सादगी के लिए उपयोग करना । यदि आप वास्तव में यह सुनिश्चित करना चाहते हैं कि यह केवल एक >क्वेरी है तो आप ARel तालिका तक पहुँच सकते हैं। प्रत्येक वर्ग जिसे विरासत में मिला है, ActiveRecordउसके पास एक arel_tableगेट्टर विधि है जो Arel::Tableउस वर्ग के लिए वापस आती है । तालिका के स्तंभों को []विधि के साथ एक्सेस किया जाता है User.arel_table[:id]। यह वह रिटर्न है जिस पर Arel::Attributes::Attributeआप कॉल कर सकते हैं gtऔर पास कर सकते हैं 200। इसके बाद इसे पारित किया जा सकता है where। उदा User.where(User.arel_table[:id].gt(200))
हारून

2
@bluehallu क्या आप एक उदाहरण प्रदान कर सकते हैं? निम्नलिखित मेरे लिए काम नहीं कर रहा है User.where(created_at: 3.days.ago..DateTime::Infinity.new)
आरोन

1
आह! यह संभावना है कि रेल 5 में एक नया बदलाव आपको लाभकारी व्यवहार दे रहा है। रेल 4.2.5 (रूबी 2.2.2) में आपको एक क्वेरी मिलेगीWHERE (users.created_at >= '2016-04-09 14:31:15' AND users.created_at < #<Date::Infinity:0x00>) (तालिका के चारों ओर पीछे की ओर टिक और एसओ टिप्पणी प्रारूप के लिए छोड़ दिया गया स्तंभ नाम)।
हारून

22

एक बेहतर उपयोग उपयोगकर्ता मॉडल में एक गुंजाइश बनाने के लिए है where(arel_table[:id].gt(id))


6

यदि आप अधिक सहज लेखन चाहते हैं, तो इसमें स्क्वील नामक एक मणि मौजूद है, जो आपको अपना निर्देश इस तरह लिखने देगा:

User.where{id > 200}

'ब्रेस' अक्षर {} और id सिर्फ एक पाठ होने के नाते।

आपको केवल अपने Gemfile में स्क्वील जोड़ना है:

gem "squeel"

रूबी में जटिल एसक्यूएल स्टेटमेंट लिखते समय यह आपके जीवन को बहुत आसान बना सकता है।


11
मैं स्क्वील का उपयोग करने से बचने की सलाह देता हूं। दीर्घकालिक बनाए रखना मुश्किल है और कभी-कभी विषम व्यवहार होता है। इसके अलावा यह कुछ सक्रिय रिकॉर्ड संस्करणों के साथ छोटी गाड़ी है
जॉन ओवेन चिली

मैं कुछ वर्षों से स्क्वील का उपयोग कर रहा हूं और अभी भी इससे खुश हूं। लेकिन शायद यह उदाहरण के लिए अगली कड़ी (<> स्क्वील) की तरह एक और ओआरएम की कोशिश करने के लायक है, जो एक्टिवरॉर्ड को बदलने के लिए अच्छी सुविधाओं का वादा करता है।
डगलस


4

एक और फैंसी संभावना है ...

User.where("id > :id", id: 100)

यदि आप कई स्थानों पर प्रतिस्थापित करना चाहते हैं, तो यह सुविधा आपको अधिक सहज प्रश्न बनाने की अनुमति देती है, उदाहरण के लिए ...

User.where("id > :id OR number > :number AND employee_id = :employee", id: 100, number: 102, employee: 1205)

यह ?क्वेरी पर बहुत कुछ होने से अधिक अर्थ है ...

User.where("id > ? OR number > ? AND employee_id = ?", 100, 102, 1205)

3

मुझे अक्सर दिनांक फ़ील्ड (जहां तुलना ऑपरेटर बहुत सामान्य हैं) के साथ यह समस्या है।

मिहाई के उत्तर के बारे में विस्तार से बताने के लिए, जो मेरा मानना ​​है कि एक ठोस दृष्टिकोण है।

मॉडल के लिए आप इस तरह से स्कोप जोड़ सकते हैं:

scope :updated_at_less_than, -> (date_param) { 
  where(arel_table[:updated_at].lt(date_param)) }

... और फिर अपने नियंत्रक में, या जहाँ भी आप अपने मॉडल का उपयोग कर रहे हैं:

result = MyModel.updated_at_less_than('01/01/2017')

... जोड़ों के साथ एक अधिक जटिल उदाहरण इस तरह दिखता है:

result = MyParentModel.joins(:my_model).
  merge(MyModel.updated_at_less_than('01/01/2017'))

इस दृष्टिकोण का एक बड़ा फायदा यह है कि यह आपको विभिन्न स्कोपों ​​से अपने प्रश्नों की रचना करने देता है और (b) जब आप दो बार एक ही तालिका में शामिल होते हैं तो alias टकराव से बचते हैं क्योंकि arel_table क्वेरी पीढ़ी के उस हिस्से को संभाल लेगा।


1

रेल्स 6.1+

नियम 6.1 ने whereशर्तों में तुलना ऑपरेटरों के लिए एक नया 'वाक्यविन्यास' जोड़ा , उदाहरण के लिए:

Post.where('id >': 9)
Post.where('id >=': 9)
Post.where('id <': 3)
Post.where('id <=': 3)

तो आपकी क्वेरी को इस प्रकार फिर से लिखा जा सकता है:

User.where('id >': 200) 

यहां पीआर के लिए एक लिंक है जहां आप अधिक उदाहरण पा सकते हैं।


-3

छोटा:

User.where("id > 200")

8
मुझे लगता है कि यह गतिशील होना चाहिए, और यह कि पोस्टर पैरामीटर प्रश्नों ( where("id > ?", 200)सिंटैक्स) का उपयोग करके SQL इंजेक्शन से बचना चाहता है । यह हासिल नहीं करता है।
मैथ्यू हिना
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.