Rails ActiveRecord WHERE EXISTS查询

Jos*_*ood 2 mysql ruby-on-rails

我有一个SQL查询,该查询返回了我需要的内容,但是我无法以“ Rails方式”将其转换为活动记录查询。

我的SQL查询是:

SELECT * from trips 
WHERE trips.title LIKE "%Thailand%"
AND EXISTS (SELECT * from places WHERE places.trip_id = trips.id AND places.name LIKE "%Bangkok%")
AND EXISTS (SELECT * from places WHERE places.trip_id = trips.id AND places.name LIKE "%Phuket%")
Run Code Online (Sandbox Code Playgroud)

我正在尝试使用Rails这样的事情:

@trips=Trip.where("trips.title LIKE ?", "%Thailand%")
@trips=@trips.includes(:places).where(("places.name LIKE ?","%Bangkok%").exists?) => true, ("places.name LIKE ?","%Phuket%").exists?) => true)
Run Code Online (Sandbox Code Playgroud)

但这似乎不起作用,我对尝试尝试感到困惑。

Rob*_*bel 13

RAILS 5/6 编辑:https://github.com/rails/rails/pull/29619开始,Rails 开始不鼓励直接.exists从我的原始答案中拨打电话。我已经更新它以使用新语法,它arel首先调用代理 ( .arel.exists)。此外,从 Rails 5 开始,哈希条件在 EXISTS 子句中工作得很好。

考虑到所有这些,纯 ActiveRecord 方法现在是:

Trip.where("trips.title LIKE ?", "%Thailand%")
    .where( Place.where('trip_id = trips.id AND name LIKE ?', '%Bangkok%').arel.exists )
    .where( Place.where('trip_id = trips.id AND name LIKE ?', '%Phuket%').arel.exists )
Run Code Online (Sandbox Code Playgroud)

如果这看起来有点吓人,您还有其他一些选择:

  • 您可以直接使用.where('EXISTS(SELECT 1 FROM places WHERE trip_id = trips.id AND name LIKE ?', '%Bangkok%'), 将 SQL 嵌入到您的应用程序中。它不是那么时髦或酷,但从长远来看,它可能更易于维护——它不太可能被弃用或停止使用未来版本的 rails。
  • 选择一个 gem,比如activerecord_where_assoc,它可以使语法更清晰,并且可以避免您犯一些简单的错误(比如没有正确地确定您的 EXISTS 查询的范围,就像我原来的答案所做的那样)。


Eug*_*Zol 6

使用存在的地方的宝石(注意:我是它的作者):

Trip.where("trips.title LIKE ?", "%Thailand%")
  .where_exists(:places, ['name LIKE ?', '%Bangkok%'])
  .where_exists(:places, ['name LIKE ?', '%Phuket%'])
Run Code Online (Sandbox Code Playgroud)

  • 不知道有这个,看起来很棒! (3认同)
  • 我明白你在那里做了什么:) (2认同)