Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/mysql/63.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Mysql Rails ActiveRecord WHERE EXISTS查询_Mysql_Ruby On Rails - Fatal编程技术网

Mysql Rails ActiveRecord WHERE EXISTS查询

Mysql Rails ActiveRecord WHERE EXISTS查询,mysql,ruby-on-rails,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

我有一个返回所需内容的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%")
我正在使用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)

但它似乎不起作用,我很困惑该怎么做。

这是我第一次尝试的重构版本,结果更接近你的预期目标。我为第一次的错误道歉

在app/models/trip.rb中:

然后你可以写:

Trip.for_title('Thailand').has_place('Bangkok').has_place('Phuket')
这将提供以下SQL:

SELECT "trips".* FROM "trips" WHERE ("trips"."title" LIKE '%Thailand%') AND (EXISTS (SELECT "places".* FROM "places" INNER JOIN "trips" ON "trips"."id" = "places"."trip_id" WHERE "places"."name" = 'Bangkok')) AND (EXISTS (SELECT "places".* FROM "places" INNER JOIN "trips" ON "trips"."id" = "places"."trip_id" WHERE "places"."name" = 'Phuket'))
这使您可以灵活地组合查询,而不必在查询中依赖硬编码SQL,并且可以在数据库引擎之间移植

此解决方案假定该位置属于Trip及其补充。如果关联不同,请调整JOIN子句

这个解决方案的部分灵感来自和。

RAILS 5/6编辑:从年开始,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 )
如果这看起来有点吓人,你还有其他选择:

您可以使用.where'exists从trip_id=trips.id和名称类似的地方选择1,'%曼谷%',直接将SQL嵌入到应用程序中。它既不时髦也不酷,但从长远来看,它可能更易于维护——它不太可能被弃用或停止使用rails的未来版本。 选择一个gem,比如,它可以使语法更清晰,并且可以避免犯一些简单的错误,比如没有正确确定EXISTS查询的范围,就像我最初的回答那样。 使用gem fair note:我是它的作者:

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

不使用gem会更容易出错。在撰写本文时,当前接受的答案是手动执行的,实际上没有生成正确的SQL。它已经被修复,但这突出了出错的风险

另一个可以做到这一点的宝石:我是作者

有了它,您可以通过以下方式做您想做的事情:

Trip.where("trips.title LIKE ?", "%Thailand%")
    .where_assoc_exists(:places, ['name LIKE ?', '%Bangkok%'])
    .where_assoc_exists(:places, ['name LIKE ?', '%Phuket%'])

通过对Rails 4.2到6.0的测试和CI测试,功能更加强大。下面是一个。

您使用的是哪个版本的Rails?我使用的是Rails 4.2.1,我正在为您准备一个较长的答案,但由于您在SQL中使用了LIKE,您可能希望查看,因为LIKE在不同的数据库中的行为不同,但这并不是您对此查询有问题的原因-只是给您一个快速警告。请查看gem这是最接近我最初尝试的解决方案,似乎是最简单的解决方案。你提到的警告并没有困扰我,因为我只需要使用LIKE,据我所知,LIKE需要文本字符串。这个答案对于将生成的SQL来说似乎是错误的。原始查询在EXISTS中有places.trip\u id=trips.id,而这里生成的查询没有,并且有一个随机的不必要的连接。因此,它似乎只是检查具有这些名称的地方是否存在,并且Trip链接到任何没有条件的地方。还有一个真正使用宝石的理由:@MaximeLapointe谢谢你指出这一点-我很惊讶它花了将近五年的时间!我已经更新了答案,以反映Rails当前的行为,还包括一个关于您的gem的说明。不知道这个存在,看起来很棒!我知道你在那里做了什么:
Trip.where("trips.title LIKE ?", "%Thailand%")
    .where_assoc_exists(:places, ['name LIKE ?', '%Bangkok%'])
    .where_assoc_exists(:places, ['name LIKE ?', '%Phuket%'])