2017-02-09 17 views
2

我想編寫一個查詢,結合兩個範圍與「OR」查詢(使用Rails 4,雖然問題仍然存在與rails 5)。ActiveRecord OR查詢與SQL中的兩個範圍,其中一個範圍有一個連接

型號1

scope :association_has_email, -> { joins(:model2).where.not(model2s:{email:nil}) } 
scope :description_has_email, -> { where("description ~* ?", email_regex) } 

(其中email_regex是一個正則表達式挑選出一個郵件)。

這給了我們SQL LIKE:

SELECT \"model1s\".* FROM \"model1s\" WHERE (description ~* '[[:<:]][A-Z0-9._%+-][email protected][A-Z0-9.-]+.[A-Z]{2,4}[[:>:]]') 
SELECT \"model1s\".* FROM \"model1s\" INNER JOIN \"model2s\" ON \"model2s\".\"id\" = \"model1s\".\"model2_id\" WHERE (\"model2s\".\"email\" IS NOT NULL) 

創建範圍,挑選出這些機會,其中任一電子郵件是在聯想或在文本嵌入的電子郵件。

如何編寫一個「OR」查詢,其中一方需要連接而另一方不需要?

+0

請參閱http://stackoverflow.com/questions/31096009/activerecord-or-query-hash-notation –

+1

使用where-or gem(這是輝煌的......)你會得到一個「ArgumentError:傳遞給#or的關係必須在結構上兼容「 但是,如果您向範圍傳遞連接,則會出現問題,如果email_in_description根本不包含model2,則將其排除。 但是,我認爲我有一個解決方案。可以通過包括獲得一個外部連接... – Carpela

+0

我總是建議人們使用原始SQL,其中ActiveRecord DSL無法成爲一個好工具。 – MurifoX

回答

0

確定。 對於導軌4,在那裏,或寶石提供一種用於產生或查詢,在導軌5的修復,但是如果傳遞的範圍你上面結束了一個

ArgumentError: Relation passed to #or must be structurally compatible 

可以使用以下:

scope :email_somewhere, -> { association_has_email.or(Model1.joins(:model2).description_has_email } 

SELECT \"model1s\".* FROM \"model1s\" INNER JOIN \"model2s\" ON \"model2s\".\"id\" = \"model1s\".\"model2_id\" WHERE ((\"model2s\".\"email\" IS NOT NULL) OR (description ~* '[[:<:]][A-Z0-9._%+-][email protected][A-Z0-9.-]+.[A-Z]{2,4}[[:>:]]')) 

工程,但它會排除任何在描述中有電子郵件但沒有model2的東西,因爲它使用內部連接。

但是通過使用includes,您可以獲得所需的結果。

scope :association_has_email, -> { includes(:model2).where.not(model2s:{email:nil}) } 
scope :description_has_email, -> { where("description ~* ?", email_regex) } 

意味着你可以使用

scope :email_somewhere, -> { association_has_email.or(Model1.includes(:model2).description_has_email } 

的區別是SQL拉所有的屬性,從模型1,然後將左外連接的MODEL2查詢。

SELECT [...all the model1 attributes...] LEFT OUTER JOIN \"model2s\" ON \"model2s\".\"id\" = \"model1s\".\"model2_id\" WHERE ((\"model2s\".\"email\" IS NOT NULL) OR (description ~* '[[:<:]][A-Z0-9._%+-][email protected][A-Z0-9.-]+.[A-Z]{2,4}[[:>:]]')) 

刺激,如果你真的需要使用內部連接的第一個,但我的作品。

0

您可以創建一個更大的空間像以下:

scope :check_email, -> { 
    if email is embedded 
    association_has_email 
    else 
    description_has_email 
    end 
} 
+0

什麼是「嵌入」在這裏? – Carpela

+0

這只是爲了檢查你要搜索的郵件地址 –

+0

有點困惑。我們要做的是查明我們的某個記錄是否有任何類型的電子郵件。我們正在設法確定我們是否有直接溝通的手段。即我們並不知道我們是否有電子郵件,這是範圍試圖過濾的內容) – Carpela

相關問題