[英]Pass array in raw MySQL query in Ruby on Rails
所以,我有一个问题。 我有一个查询从一个表(比如table1)返回id,我必须将这些id传递给另一个使用table2的查询。 (由于某些原因,编写内部选择或连接不是一种选择)。
查询:
client = Mysql2::Client.new(:host => "localhost", :username => "", :password => "", :database =>"test")
query1 = %Q{select id from table1 where code='ABC123'}
ids = client.query(query1)
query2 = %Q{select * from table2 where `table2`.`table1_id` IN (#{ids}) and status="rejected"}
table2_data = client.query(query2)
ids是Mysql2 :: Result type另外,当我执行ids.to_a时,结果数组的数据如下:[{“id”=> 1},{“id”=> 2}]我需要一些可行的方法将id传递给第二个查询。 我尝试了ids.to_a,但由于括号[]而导致错误。 我也试过连接,说MySQL的结果是:
array = ids.to_a # [1,2,3]
id_new = "("+#{array.join(',')}+")"
id_new变为“(1,2,3)”,这是一个字符串,因此IN不起作用。
任何人都可以建议如何在原始MySQL查询中传递ids数组? 我发现了答案,但找不到合适的答案。
编辑 :我只能为查询1使用Active Record,如果是这种情况,并且ids是一个Active Record对象,有人可以建议如何将它传递给IN子句中的query2,它应该是一个原始的SQL查询吗?
Edit2 :我不能使用Active Record(用于query2)或加入,因为它使查询繁重并花费很长时间(> 10s)来获取结果(索引存在)。 所以,我正在使用原始查询来优化它。
你确定它不起作用,因为它是一个字符串。 我认为它不起作用,因为重复括号。 请试试这个:
array = ids.flat_map(&:values).join(',')
query2 = %Q{select * from table2 where `table2`.`table1_id` IN (#{array}) and status="rejected"}
我建议使用像ActiveRecord
或Sequel
宝石一样的ORM(对象关系映射) - 特别是因为通过字符串连接手动构建数据库查询容易出错并导致sql注入等漏洞。
当我跑了类似的查询,试图模仿你的问题,我看到我得到数组的数组, ids
,如[["1"], ["2"], ["3"]]
如果这也是你得到的,那么你应该在调用join
之前调用ids.flatten
:
query2 = %Q{select * from table2 where `table2`.`table1_id` IN (#{ids.flatten.join(',')}) and status="rejected"}
array.flatten
删除额外的大括号,所以:
[[1], [2], [3]].flatten
# => [1,2,3]
[[1], [2], [3]].flatten.join(',')
# => "1,2,3"
编辑
由于您报告您正在接收Mysql2::Result
对象,请执行以下操作: ids.to_a.map(&:values).flatten.join(',')
to_a
首先将Mysql2::Result
转换为Mysql2::Result
的哈希数组:
[{"id"=>"1"}, {"id"=>"2"}]
然后使用map(&:values)
我们将其转换为如下所示的数组:
[["1"], ["2"]]
此数组类似于上面(在编辑之前),因此运行flatten.join(',')
会将其转换为您要查找的字符串。
请注意,您可以使用公共快捷方式flat_map(&:values)
代替map(&:values).flatten
,这会产生相同的结果。
如果您发布的主要原因是学习如何从散列数组中提取数据,那么您可以忽略此答案。
但是,如果您想从数据库中获取数据的最佳方法,我建议您使用ActiveRecord
为您执行驴工作:
class Table1 < ActiveRecord::Base
self.table_name = :table1
has_many :table2s
end
class Table2 < ActiveRecord::Base
self.table_name = :table2
belongs_to :table1
end
table2_data = Table2.joins(:table1).where(table1: {code: 'ABC123'}, status: 'rejected')
关键是SQL
join
将有效地为您处理ID。 您可以自己编写SQL
连接的代码,但ActiveRecord
会为您执行此操作,并允许您添加其他查询,以便您可以在一个查询中收集所需的数据。
您可以使用comma
连接数组,如下面的代码。
ids = ids.to_a.map{|h| h['id']}
query2 = %Q{select * from table2 where `table2`.`table1_id` IN (#{ids.join(',')}) and status="rejected"}
table2_data = client.query(query2)
它会工作正常。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.