ActiveRecord VEYA sorgusu


181

Rails 3 ActiveRecord bir OR sorgusu nasıl yapılır. Bulduğum tüm örneklerde VE sorguları var.

Düzenleme: OR yöntemi Rails 5'ten beri kullanılabilir. Bkz. ActiveRecord :: QueryMethods


7
SQL öğrenin. ActiveRecord, işleri çalıştırmayı kolaylaştırır, ancak yine de sorgularınızın ne yaptığını bilmeniz gerekir, aksi takdirde projeniz ölçeklendirilmeyebilir. Ayrıca SQL ile uğraşmak zorunda kalmadan alabileceğimi düşündüm ve bu konuda çok yanılmışım.
ryan0

1
@ ryan0, haklısın. Süslü taşlar ve diğer şeyleri kullanabiliriz, ancak bu mücevherlerin içeride ne yaptığını ve altta yatan teknolojinin ne olduğunu bilmeliyiz ve belki de ihtiyaç duyulursa, gemin yardımı olmadan altta yatan teknolojileri kullanmalıyız. verim. Taşlar, belirli sayıda kullanım göz önünde bulundurularak oluşturulur, ancak projemizdeki kullanıcı tabanından birinin farklı olabileceği durumlar olabilir.
rubyprince


1
Rails 5'ten beri, IMHO kabul edilen cevap Greg Olsen versiyonu olmalıdır:Post.where(column: 'something').or(Post.where(other: 'else'))
Philipp Claßen

6
Bu sorunun bir ruby-on-rails-3 etiketi var. Kabul edilen cevap neden yalnızca Rails 5 ile ilgilidir?
iNulty

Yanıtlar:


109

ARel kullanın

t = Post.arel_table

results = Post.where(
  t[:author].eq("Someone").
  or(t[:title].matches("%something%"))
)

Ortaya çıkan SQL:

ree-1.8.7-2010.02 > puts Post.where(t[:author].eq("Someone").or(t[:title].matches("%something%"))).to_sql
SELECT     "posts".* FROM       "posts"  WHERE     (("posts"."author" = 'Someone' OR "posts"."title" LIKE '%something%'))

Biraz dağınık hissettiriyor, ama en azından sql yazmıyorum, ki bu sadece yanlış geliyor! Arel’yi daha çok kullanmayı düşünmem gerekecek.
pho3nixf1re

55
Sequel'in ne kadar daha zarif olduğuna inanamıyorum
Macario

3
SQL'de yanlış bir şey yok. Yanlış gidebilecek şey, SQL dizesini yani SQL Injection'ı nasıl oluşturduğumuz . Bu nedenle, veritabanına karşı çalıştırılması gereken bir SQL sorgusu sağlamadan önce kullanıcı girdisini sterilize etmemiz gerekecek. Bu tarafından ele alınacaktır orm ler ve bu biz bayan eğiliminde olduğunu, kenar davalarına edilmiştir. Bu nedenle, SQL sorguları oluşturmak için ORM kullanılması her zaman tavsiye edilir .
rubyprince

5
SQL ile ilgili bir diğer sorun ise veritabanı agnostik olmamasıdır. Örneğin sqlite (varsayılan olarak büyük / küçük harfe duyarsız) ve postgres (operatör gibi açık büyük / küçük harfe duyarlı değildir ) matchesüretir . LIKEILIKE
amoebe

1
@ToniLeigh ActiveRecord başlık altında SQL kullanıyor. Bu, SQL temizliğini işleyen ve sorgularınızı DB agnostik hale getiren SQL sorguları yazmak için bir sözdizimidir. Tek yük, Rails'in sözdizimini SQL sorgusuna dönüştürdüğü yerdir. Ve bu sadece milisaniye meselesidir. Tabii ki en iyi performans gösteren SQL sorgusunu yazmalı ve ActiveRecord sözdizimine dönüştürmeye çalışmalısınız. SQL ActiveRecord sözdiziminde temsil edilemiyorsa, düz SQL için gitmelisiniz.
rubyprince

208

Bir sütunun değerinde OR işleci kullanmak istiyorsanız, bir dizi iletebilirsiniz .whereve ActiveRecord şunları kullanır IN(value,other_value):

Model.where(:column => ["value", "other_value"]

çıktılar:

SELECT `table_name`.* FROM `table_name` WHERE `table_name`.`column` IN ('value', 'other_value')

Bu, ORtek bir sütundaki a değerine eşdeğer olmalıdır


13
Bu en temiz "raylar yolu" cevabı, kabul edilmelidir
koonse

10
Teşekkürler @koonse, tam olarak bir 'VEYA' sorgusu değil, ancak bu durum için aynı sonucu üretir.
deadkarma


80
Bu çözüm, iki farklı sütunu bu şekilde kullanamayacağınız için OR yerine geçmez.
fotanus

152

Rails 3'te,

Model.where("column = ? or other_column = ?", value, other_value)

Bu da ham sql içerir ama ActiveRecord VEYA işlemi yapmak için bir yol olduğunu sanmıyorum. Sorunuz bir noob sorusu değil.


41
Ham sql olsa bile - bu ifade benim için Arel'den çok daha net görünüyor. Belki DRYer bile.
jibiel

6
zincirlemeniz gerekiyorsa, aynı sütun adlarına sahip sütunlara sahip olabilecek diğer tablo birleşimleri, bunu böyle kullanmalısınız,Page.where("pages.column = ? or pages.other_column = ?", value, other_value)
rubyprince

1
Sorgu tabloları takma yapar ve bu başarısız olur. O zaman arel parlıyor.
DGM

58

Rails / ActiveRecord'un güncellenmiş bir sürümü bu sözdizimini yerel olarak destekleyebilir. Şuna benzer görünecektir:

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

Bu çekme isteğinde belirtildiği gibi https://github.com/rails/rails/pull/9052

Şimdilik, sadece aşağıdakilere sadık kalmak harika çalışıyor:

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

Güncelleme: göre https://github.com/rails/rails/pull/16052or özelliği Raylar satışa sunulacak 5

Güncelleme: Özellik Rails 5 şubesine birleştirildi


2
orşu anda kullanılabilir Rails 5, ancak 1 argümanın iletilmesini beklediğinden bu şekilde uygulanamaz. Bir Arel nesnesi bekliyor. Kabul edilen yanıtı görün
El'Magnifico

2
orActiveRecord yöntem doğrudan kullandığınız eğer çalışır: ama daha sonra zincirlenmiş bir kapsamda kullanılır eğer beklentilerinizi kırabilir.
Jeremy List

@JeremyList'in söyledikleri yerinde. Beni biraz zorladı.
courtsimas


23

Raylar 5 bir oryöntemle gelir . (l dokümanlara mürekkep )

Bu yöntem bir ActiveRecord::Relationnesneyi kabul eder . Örneğin:

User.where(first_name: 'James').or(User.where(last_name: 'Scott'))

14

Dizileri bağımsız değişken olarak kullanmak isterseniz, Rails 4'te aşağıdaki kod çalışır:

query = Order.where(uuid: uuids, id: ids)
Order.where(query.where_values.map(&:to_sql).join(" OR "))
#=> Order Load (0.7ms)  SELECT "orders".* FROM "orders" WHERE ("orders"."uuid" IN ('5459eed8350e1b472bfee48375034103', '21313213jkads', '43ujrefdk2384us') OR "orders"."id" IN (2, 3, 4))

Daha fazla bilgi: VEYA Rails 4'te bağımsız değişken olarak dizileri sorgular .


9
Veya bu: Order.where(query.where_values.inject(:or))arel'i sonuna kadar kullanmak.
Cameron Martin

> VEYA Rails 4'te argümanlar olarak dizilerle sorgular. Teşekkürler!
Zeke Fast

7

MetaWhere eklentisi tamamen şaşırtıcı.

OR'leri ve AND'leri kolayca karıştırın, herhangi bir ilişkilendirmedeki koşullara katılın ve hatta OUTER JOIN'ları belirtin!

Post.where({sharing_level: Post::Sharing[:everyone]} | ({sharing_level: Post::Sharing[:friends]} & {user: {followers: current_user} }).joins(:user.outer => :followers.outer}

6

Koşullara bir OR ekleyin

Model.find(:all, :conditions => ["column = ? OR other_column = ?",value, other_value])

4
Bu daha çok Rails 2 sözdizimidir ve bir sql dizesinin en azından bir kısmını yazmamı gerektirir.
pho3nixf1re

3

Bu eklentiyi.or. , eski, kapsamları birleştirmenize izin veren istemci çalışmasından çıkardım . Post.published.or.authored_by(current_user). Squeel (MetaSearch'ün daha yeni uygulanması) da harika, ancak OR kapsamlarını belirlemenize izin vermiyor, bu nedenle sorgu mantığı biraz gereksiz olabilir.


3

Raylar + arel ile daha net bir yol:

# Table name: messages
#
# sender_id:    integer
# recipient_id: integer
# content:      text

class Message < ActiveRecord::Base
  scope :by_participant, ->(user_id) do
    left  = arel_table[:sender_id].eq(user_id)
    right = arel_table[:recipient_id].eq(user_id)

    where(Arel::Nodes::Or.new(left, right))
  end
end

üretir:

$ Message.by_participant(User.first.id).to_sql 
=> SELECT `messages`.* 
     FROM `messages` 
    WHERE `messages`.`sender_id` = 1 
       OR `messages`.`recipient_id` = 1

3

Bunu şöyle yapabilirsiniz:

Person.where("name = ? OR age = ?", 'Pearl', 24)

veya daha zarif, rails_or gem yükleyin ve şöyle yapın:

Person.where(:name => 'Pearl').or(:age => 24)

-2

Bu bir ActiveRecord birden çok özniteliği aramak için bir çözüm eklemek istiyorum. Dan beri

.where(A: param[:A], B: param[:B])

A ve B'yi arayacaktır.


-4
Book.where.any_of(Book.where(:author => 'Poe'), Book.where(:author => 'Hemingway')

2
Cevabınıza bazı açıklamalar ekleyin
kvorobiev

1
Matthew bu sözdizimi için destek ekler activerecord_any_of gem atıfta olduğuna inanıyorum .
DannyB

2
Eğer doğruysa, @ DannyB teşekkürler. Cevap bağlamını açıklamalıdır.
Sebastialonso
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.