2011-07-26 10 views
10

It adlı defa katılır ile update_all yapmak. istekli yükleme ileham SQL Rails'in soyutlama bana kafayı sürücüler böyle Rails

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 

nasıl Raylar 3.0.1 yapabilirsiniz: MySQL bunu yapabilir miydim? Aşağıdakilerin tümünü denedim:

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

Yukarıdakilerin tüm varyasyonları. Hepsi ya hata verdi ya da bir şey bulamadı.

Sonra scope kullanmaya çalıştı:

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 

Bu seferki bana hata undefined method 'to_sym' for #<Hash:0x1065c6438> verdi.

Sadece basit bir SQL sorgusu çoğaltmak için, bu konuda yol çok uzun saatler geçirdim. Lütfen yardım et!


DÜZENLEME: Geçici kötü çözüm etrafında almak 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(',')})"] 

cevap

3

"DAN GÜNCELLEME" değil standart SQL olduğunu, doğrudan desteklemediği eğer şaşırtıcı değil bu yüzden Aktif Kayıt Ancak, Active kayıt size onun soyutlamalar atlamak ve bunu desteklemez bir şeyler yapmak varken sadece o zamanlar için, düz SQL vermek için bir yol vermek yok. Bir model İçinde:

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 :: Base de sağlayan bir "select_by_sql" yöntemi vardır, standart olmayan seçme ifadeleri düzenli aktif rekor modeli örnekleri dönmek.

+0

Teşekkürler, Wayne. Mümkünse soyutlamak isterim çünkü SQL'in farklı tatları bu tür bir sorguyu oldukça farklı bir şekilde ele alıyor ve gelecekte kırılmasından endişeleniyorum. Yukarıdaki örneğim, "görevleri güncelleştir, proje ayarları ..." olarak değiştirilebilir ve hala sorun yaşıyorum. Başka düşüncelerin varsa, bunu takdir ediyorum! – glortho

+0

@Jed, Bu da standart olmayan bir SQL olurdu. Active Record'un bunu nasıl soyutlatacağını bilmiyorum. SQL ile yapabileceğiniz bazı şeyler CRUD soyutlama ile çok iyi uyuşmuyor. Bu özellikle. –

+0

İlginç. Yani 1 + n (istekli olmayan yükleme) soyutlama katmanında bunu yapmanın tek yolu gerçekten mi? Şüphem ki, 'bir şekilde bir çözüm sunmuyor. Yukarıdaki ikinci eforum gibi bir şey işe yaramaz mı? Şimdilik 1 + n ile gidiyor ama kesinlikle sürdürülebilir bir çözüm değil. Yardımınız için teşekkürler ... – glortho

0

aşağıdaki

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 

aşağıdaki Arel sorgu olarak yazılmış olabilir inanıyoruz:

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

Bu Çalışma ve Projelerin arasında doğru ilişki olduğunu varsayar.

2

Bu tamamen yakut/raylar, bu SQL olarak etiketlenmiş olmamalıdır edilir -

Alabileceğiniz tek bir SQL bilgisi olan: Başka bir sözdizimsel eşdeğeri yerine standart değil "dan güncelleme" dan başlamak, Örneğin bu gibi (ki ben de yapmazdım ama hey rubi/ray kullanmıyorum).

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

Ben 3.0.8 ve AREL 2.0.10, doğrudan DAN UPDATE üretmek olamazdı raylar @ en azından inanmak, ama bir alt sorgu olarak katılmak gidererek ile aynı sonucu almak mümkündür , Örneğin Bu SQL değil Rails alt sorgu çözme oluyor, Ourse

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 

:

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

Bu gibi SQL oluşturur.Bir alt-select SQL oluşturmak için, böyle küçük Arel'de karıştırabilirsiniz:

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) 

bu gibi sql üretir Hangi:

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 
); 

Orada Bunu yapmanın saf AREL yolu ama UpdateManager sözdizimi, çok az belgelenmiş

İlgili konular