2011-07-26 7 views
10

यह बार मिलती है के साथ एक update_all कर। MySQL में मैं यह कर सकता था:रेल में यह है कि कच्चे एसक्यूएल से रेल 'अमूर्त मुझे बैटी ड्राइव की तरह

UPDATE FROM tasks AS t 
LEFT JOIN projects as p 
ON t.project_id = p.id 
SET t.invoice_id = 7 
WHERE p.organization_id == 42 
AND t.invoice_id IS NULL 

मैं रेल लोड 3.0.1 में उत्सुक लोडिंग के साथ यह कैसे कर सकता हूं? इसके बाद के संस्करण के रूपांतरों का

Tasks.joins(:project).where('projects.organization_id' => 42, :invoice_id => nil).update_all(:invoice_id => 7) 

और यह सब: मैं निम्न में से सभी की कोशिश की है। सभी ने या तो त्रुटियां दीं या कुछ भी नहीं मिला।

तब मैं scope का उपयोग करने की कोशिश की:

Task.scope :find => {:joins => :project, :conditions => ["projects.organization_id == ? AND invoice_id IS NULL", @organization.id] } do 
    Task.update_all :invoice_id => @invoice.id 
end 

यह भी मुझे त्रुटि undefined method 'to_sym' for #<Hash:0x1065c6438> दे दी है।

मैं इस पर जिस तरह से भी कई घंटे खर्च किया है, बस एक साधारण SQL क्वेरी को दोहराने के लिए। कृपया सहायता कीजिए!


संपादित करें: अस्थायी बुरा समाधान के आसपास पाने के लिए n + 1:

task_ids = Task.select('tasks.id').joins(:project).where('projects.organization_id' => @organization.id, :invoice_id => nil).collect{|t| t.id} 
Task.update_all ['invoice_id = ?', @invoice.id], ["id in (#{task_ids.join(',')})"] 

उत्तर

3

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

sql = "UPDATE FROM tasks AS t 
LEFT JOIN projects as p 
ON t.project_id = p.id 
SET t.invoice_id = 7 
WHERE p.organization_id == 42 
AND t.invoice_id IS NULL" 
connection.update_sql(sql) 

ActiveRecord :: बेस भी एक "select_by_sql" विधि देता है कि है अपने गैर मानक का चयन बयान नियमित सक्रिय रिकॉर्ड मॉडल उदाहरणों लौट आते हैं।

+0

धन्यवाद, वेन। यदि संभव हो तो मैं सारण करना चाहता हूं क्योंकि एसक्यूएल के विभिन्न स्वाद इस प्रकार की क्वेरी को काफी अलग तरीके से संभालते हैं और मैं भविष्य में इसे तोड़ने के बारे में चिंतित हूं। ऊपर मेरा उदाहरण 'अपडेट कार्यों, परियोजनाओं सेट ...' में बदल दिया जा सकता है और मुझे अभी भी परेशानी होगी। यदि आपके पास और विचार हैं तो मैं इसकी सराहना करता हूं! – glortho

+0

@ जेड, यह गैर मानक एसक्यूएल भी होगा। मुझे नहीं पता कि सक्रिय रिकॉर्ड कैसे अमूर्त होगा। एसक्यूएल के साथ आप कुछ चीजें कर सकते हैं जो सीआरयूडी अबास्ट्रक्शन से बहुत अच्छी तरह से मेल नहीं खाते हैं। यह विशेष रूप से। –

+0

दिलचस्प। तो 1 + एन (गैर-उत्सुक लोडिंग) वास्तव में अबास्ट्रक्शन परत में ऐसा करने का एकमात्र तरीका है? मैं विश्वास नहीं कर सकता कि 'स्कोप' किसी भी तरह से समाधान प्रदान नहीं करता है। काम से ऊपर मेरे दूसरे प्रयास की तरह कुछ नहीं होना चाहिए? अभी के लिए सिर्फ 1 + एन के साथ जा रहा है लेकिन निश्चित रूप से एक स्थायी समाधान नहीं है। आपकी मदद के लिए धन्यवाद ... – glortho

0

मुझे विश्वास है कि निम्नलिखित

UPDATE FROM tasks AS t 
LEFT JOIN projects as p 
ON t.project_id = p.id 
SET t.invoice_id = 7 
WHERE p.organization_id == 42 
AND t.invoice_id IS NULL 

निम्नलिखित अरेल प्रश्न के रूप में लिखा जा सकता है:

Tasks.include(:projects).where("projects.organization_id = ?", 42).where("tasks.invoice_id IS NULL").update_all("tasks.invoice_id = ?", 7) 

इसका मतलब यह है कि आप कार्यों और परियोजनाओं के बीच सही संघ है।

2

यह विशुद्ध रूप से गहरे लाल रंग का/रेल, यह एसक्यूएल के रूप में चिह्नित नहीं किया जाना चाहिए है -

केवल एसक्यूएल जानकारी आपको मिल सकता है: के बजाय एक और वाक्यात्मक समकक्ष "से अद्यतन" जो मानक नहीं है से शुरू करते हैं, उदाहरण के लिए यह (जो मैं नहीं करता लेकिन हे, मैं रूबी/रेल का उपयोग नहीं करता)।

UPDATE tasks t 
SET t.invoice_id=7 
WHERE 
t.invoice_id IS NULL 
AND 
(SELECT 
p.organization_id 
FROM tasks t2 
LEFT JOIN projects p 
ON t.project_id=p.id 
WHERE t2.id=t.id)=42 
3

मैं कम से कम विश्वास है @ रेल 3.0.8 और अरेल 2.0.10, हम सीधे से अद्यतन उत्पन्न नहीं कर सकता है, लेकिन यह एक उप क्वेरी के रूप में शामिल होने को हल करने से के साथ एक ही परिणाम प्राप्त करने के लिए संभव है उदाहरण के लिए

Task.where(:invoice_id=>nil). 
where(:project_id=>Project.where(:organization_id=>42).collect(&:id)). 
update_all(:invoice_id => 7) 

इस तरह एसक्यूएल उत्पन्न करता है:

UPDATE "tasks" 
SET "invoice_id" = 7 
WHERE "invoice_id" IS NULL AND "project_id" IN (1,2,3); 
-- assuming projects 1,2,3 have organization_id = 42 

ourse में से, कि SQL में रेल में उप क्वेरी को हल नहीं।एक उप चयन एसक्यूएल में उत्पन्न करने के लिए, तो आप इस तरह एक छोटे से अरेल में मिश्रण कर सकते हैं:

t = Task.arel_table 
p = Project.arel_table 
Task.where(:invoice_id=>nil). 
where(
    t[:project_id].in(
    p.where(
     p[:organization_id].eq(42) 
    ).project(p[:id]) 
) 
).update_all(:invoice_id => 7) 

कौन इस तरह एसक्यूएल उत्पन्न करता है:

UPDATE "tasks" 
SET "invoice_id" = 7 
WHERE "invoice_id" IS NULL 
AND "project_id" IN (
SELECT "projects"."id" FROM "projects" 
WHERE "projects"."organization_id" = 42 
); 

ऐसा करने का एक शुद्ध अरेल रास्ता नहीं है, लेकिन UpdateManager वाक्यविन्यास बुरी तरह से प्रलेखित

संबंधित मुद्दे