我想写一个查询,它将两个范围与" OR"查询(使用Rails 4虽然问题仍然存在于rails 5中)。
型号1
scope :association_has_email, -> { joins(:model2).where.not(model2s:{email:nil}) }
scope :description_has_email, -> { where("description ~* ?", email_regex) }
(其中email_regex是挑选电子邮件的正则表达式)。
这为我们提供了如下SQL:
SELECT \"model1s\".* FROM \"model1s\" WHERE (description ~* '[[:<:]][A-Z0-9._%+-]+@[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)
创建一个范围,以选择电子邮件位于关联中的机会或文本中嵌入的电子邮件。
你如何写一个&#34; OR&#34;查询一方需要加入而另一方不需要?
答案 0 :(得分:0)
您可以再创建一个范围,如下所示:
Caused by: org.springframework.context.NoSuchMessageException: No message found under code 'Pattern.book.name' for locale 'en'.
at org.springframework.context.support.DelegatingMessageSource.getMessage(DelegatingMessageSource.java:84)
at org.springframework.context.support.AbstractApplicationContext.getMessage(AbstractApplicationContext.java:1264)
at org.springframework.web.servlet.support.RequestContext.getMessage(RequestContext.java:733)
at org.springframework.web.servlet.support.BindStatus.initErrorMessages(BindStatus.java:181)
at org.springframework.web.servlet.support.BindStatus.getErrorMessages(BindStatus.java:277)
at org.thymeleaf.spring4.processor.attr.SpringErrorsAttrProcessor.processAttribute(SpringErrorsAttrProcessor.java:82)
at org.thymeleaf.processor.attr.AbstractAttrProcessor.doProcess(AbstractAttrProcessor.java:87)
at org.thymeleaf.processor.AbstractProcessor.process(AbstractProcessor.java:212)
... 119 more
答案 1 :(得分:0)
确定。 对于Rails 4,where-or gem提供了生成或查询的修复,如rails 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._%+-]+@[A-Z0-9.-]+.[A-Z]{2,4}[[:>:]]'))
可以使用,但它会排除描述中包含电子邮件但没有model2的任何内容,因为它使用内部联接。
但是通过使用包含,您可以获得所需的结果。
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从model1中提取所有属性,然后为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._%+-]+@[A-Z0-9.-]+.[A-Z]{2,4}[[:>:]]'))
如果你真的需要为第一个使用内部联接,那就会激怒,但对我有效。