استعلام القضبان المعقدة - النقابات؟اختيار فرعي؟هل لا يزال بإمكاني استخدام name_scope؟

StackOverflow https://stackoverflow.com/questions/1021018

سؤال

جزء من سبب حبي لـ Rails هو أنني أكره SQL - أعتقد أنها أشبه بلغة تجميع يجب معالجتها بأدوات ذات مستوى أعلى مثل ActiveRecord.يبدو أنني قد وصلت إلى حدود هذا النهج، وأنا خارج نطاق فهمي مع SQL.

لدي نموذج معقد يحتوي على الكثير من السجلات الفرعية.لدي أيضًا مجموعة من 30 إلى 40 نطاقًا مسمىًا تنفذ منطق العمل من العميل.يتم ربط هذه النطاقات معًا بشكل مشروط، ولهذا السبب لدي تلك النطاقات joins_ النطاقات حتى لا تتعرض الروابط للضرب.

لدي اثنين منها لا يعملان بشكل صحيح، أو على الأقل لا يعملان بالشكل الذي يريده العميل.فيما يلي فكرة تقريبية عن بنية النموذج، مع بعض النطاقات المسماة (ليست كلها مطلوبة للمثال) التي توضح نهجي وتشير إلى مشاكلي. (يرجى أن يغفر أي أخطاء في بناء الجملة)

class Man < ActiveRecord::Base
  has_many :wives

  named_scope :has_wife_named       lambda { |n| { :conditions => { :wives => {:name => n}}}}
  named_scope :has_young_wife_named lambda { |n| { :conditions => { :wives => {:name => n, :age => 0..30}}}}
  named_scope :has_yw_named_v2      lambda { |n| { :conditions => ["wives.name = ? AND wives.age <= 30", n]}}
  named_scope :joins_wives         :joins => :wives

  named_scope :has_red_cat          :conditions => { :cats => {:color => 'red'}}        
  named_scope :has_cat_of_color     lambda { |c| { :conditions => { :cats => {:color => c}}}}
  named_scope :has_7yo_cat          :conditions => { :cats => {:age => 7}}
  named_scope :has_cat_of_age       lambda { |a| { :conditions => { :cats => {:age => a}}}}
  named_scope :has_cat_older_than   lambda { |a| { :conditions => ["cats.age > ?", a] }}
  named_scope :has_cat_younger_than lambda { |a| { :conditions => ["cats.age < ?", a] }}
  named_scope :has_cat_fatter_than  lambda { |w| { :conditions => ["cats.weight > ?", w] } }
  named_scope :joins_wives_cats     :joins => {:wives => :cats}
end

class Wife < ActiveRecord::Base
  belongs_to :man
  has_many :cats
end

class Cat < ActiveRecord::Base
  belongs_to :wife
end
  1. يمكنني العثور على رجال لديهم قطط زوجاتهم حمراء وعمرها سبع سنوات

    @men = Man.has_red_cat.has_7yo_cat.joins_wives_cats.scoped({:select => 'DISTINCT men'})
    

    ويمكنني أيضًا العثور على رجال لديهم قطط يزيد وزن زوجاتهم عن 20 رطلاً ويزيد عمرها عن 6 سنوات

    @men = Man.has_cat_fatter_than(20).has_cat_older_than(5).joins_wives_cats.scoped({:select => 'DISTINCT men'})
    

    ولكن هذا ليس ما أريد.أريد العثور على الرجال الذين يوجد بين زوجاتهم قطة حمراء واحدة على الأقل وقطة واحدة تبلغ من العمر سبع سنوات، والتي لا يلزم أن تكون نفس القطة، أو العثور على الرجال الذين يوجد بين زوجاتهم قطة واحدة على الأقل فوق وزن معين و قطة واحدة أكبر من عمر معين.
    (في الأمثلة اللاحقة، يرجى افتراض وجود المناسب joins_ و DISTINCT)

  2. أستطيع أن أجد رجالاً لديهم زوجات تدعى إستير

    @men = Man.has_wife_named('Esther')
    

    يمكنني حتى أن أجد رجالًا لديهم زوجات تدعى إستير أو روث أو آدا (لطيفة!)

    @men = Man.has_wife_named(['Esther', 'Ruth', 'Ada'])
    

    لكني أريد أن أجد رجالًا لديهم زوجات يُسمون إستير وراعوث وآدا.

  3. هههه فقط أمزح، في الواقع، أريد هذا:يمكنني العثور على رجال لديهم زوجات أقل من 30 عامًا يُدعى إستير

    @men = Man.has_young_wife_named('Esther')
    

    ابحث عن رجال لديهم زوجات شابات يُدعى إستير أو روث أو آدا

    @men = Man.has_young_wife_named(['Esther', 'Ruth', 'Ada'])
    

    ولكن كما هو مذكور أعلاه، أريد العثور على رجال لديهم زوجات شابات يُدعى إستير وراعوث وآدا.ولحسن الحظ، الحد الأدنى ثابت في هذه الحالة، ولكن سيكون من الجيد تحديد حد أدنى للعمر أيضًا.

  4. هل هناك طريقة لاختبار عدم المساواة باستخدام بناء جملة التجزئة، أم أنه يتعين عليك دائمًا الرجوع إليها :conditions => ["", n] - لاحظ الفرق بين has_young_wife_named و has_yw_named_v2 - أحب الأول أكثر، لكن النطاق يعمل فقط مع القيم المحدودة.إذا كنت تبحث عن زوجة عجوز، أعتقد أنه يمكنك الاستفادة منها a..100 ولكن بعد ذلك عندما تبلغ الزوجة 101 عامًا، تتوقف عن البحث. (همم.هل هي تستطيع الطبخ؟ي / ك)

  5. هل هناك طريقة لاستخدام نطاق داخل النطاق؟أنا أحب ذلك إذا :has_red_cat يمكن استخدامها :has_cat_of_color بطريقة أو بأخرى، أو إذا كانت هناك طريقة ما لاستخدام النطاق من سجل فرعي في سجله الأصلي، حتى أتمكن من وضع النطاقات ذات الصلة بالقطط في Wife نموذج.

لا أريد حقًا القيام بذلك في لغة SQL مباشرة دون استخدام named_scope, ، ما لم يكن هناك شيء آخر أفضل بالفعل - اقتراحات للمكونات الإضافية وما لا يحظى بتقدير كبير، أو التوجيه إلى نوع SQL الذي سأحتاج إلى تعلمه.اقترح أحد الأصدقاء أن عمليات البحث الفرعية أو UNIONs ستعمل هنا، ولكن لا يبدو أنها تمت مناقشتها كثيرًا في سياق Rails.لا أعرف حتى الآن أي شيء عن طرق العرض - هل ستكون مفيدة؟هل هناك طريقة سعيدة لصنع القضبان؟

شكرًا لك!

كما كنت ذاهبا إلى سانت آيفز
التقيت برجل لديه سبع زوجات
وكان لكل زوجة سبعة أكياس
كان في كل كيس سبع قطط
كان لكل قطة سبع مجموعات
أطقم، قطط، أكياس، زوجات
كم عدد الذين كانوا ذاهبين إلى سانت آيفز؟

هل كانت مفيدة؟

المحلول

حسنًا، لقد حصلت على نتائج رائعة مع named_scopeمثل هذه:

named_scope :has_cat_older_than   lambda { |a| { :conditions => ["men.id in ( select man_id from wives where wives.id in ( select wife_id from cats where age > ? ) )", a] } }

و

named_scope :has_young_wife_named lambda { |n| { :conditions => ["men.id in ( select man_id from wives where name = ? and age < 30)", n] } }

أستطيع الآن أن أفعل ذلك بنجاح

Member.has_cat_older_than(6).has_young_wife_named('Miriam').has_young_wife_named('Vashti')

والحصول على ما أتوقع.لا تتطلب هذه النطاقات استخدام الصلات، ويبدو أنها تعمل بشكل جيد مع الصلات ذات الأنماط الأخرى.

w00t!

تم التعليق على ما إذا كانت هذه طريقة فعالة للقيام بذلك، أو ما إذا كانت هناك طريقة أكثر "سككًا".قد تكون طريقة ما لتضمين نطاق من نموذج آخر كجزء من استعلام فرعي SQL مفيدًا ...

نصائح أخرى

لقد استخدمت build_finder_sql لإنجاز التحديد الفرعي لنطاق مسمى داخل نطاق آخر.قد لا يكون مناسبًا للجميع، ولكن استخدامه يسمح لنا بتجفيف بعض النطاقات المسماة التي استخدمناها للتقارير.

Man.has_cat_older_than(6).send(:construct_finder_sql,{})

جرب ذلك في البرنامج النصي/وحدة التحكم الخاصة بك.

لقد استخدمت الحل الأكثر أصالة لـ Rails.سيكون لـ Straight SQL نفس الأداء لذا لا يوجد سبب لاستخدامه.

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top