在Ruby on Rails中传递原始MySQL查询中的数组

时间:2015-11-12 06:34:48

标签: mysql ruby-on-rails ruby

所以,我有一个问题。我有一个查询从一个表(比如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类型 此外,当我执行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数组? 我发现了答案,但找不到合适的答案。

编辑:我只能对query1使用Active Record,如果是这种情况,并且ids是Active Record对象,任何人都可以建议如何在IN子句中将它传递给query2是一个原始的SQL查询?

Edit2 :我无法使用Active Record(用于query2)或加入,因为它会使查询繁重并需要很长时间(> 10s)来获取结果(索引存在)。所以,我正在使用原始查询来优化它。

4 个答案:

答案 0 :(得分:2)

你确定它不起作用,因为它是一个字符串。我认为它不起作用,因为重复括号。请试试这个:

array = ids.flat_map(&:values).join(',')
query2 = %Q{select * from table2 where `table2`.`table1_id` IN (#{array}) and status="rejected"}

我建议使用ORM (object-relational mapping)ActiveRecord宝石之类的Sequel - 特别是因为通过字符串连接手动构建数据库查询容易出错并导致sql注入等漏洞。

答案 1 :(得分:2)

当我运行类似的查询以尝试模仿您的问题时,我看到我正在获取ids的数组数组,例如[["1"], ["2"], ["3"]]

如果这也是你得到的,那么你应该在致电ids.flatten之前致电join

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转换为如下所示的哈希数组:

[{"id"=>"1"}, {"id"=>"2"}]

然后使用map(&:values)我们将其转换为如下所示的数组:

[["1"], ["2"]]

此数组与上述(编辑前)类似,因此运行flatten.join(',')会将其转换为您要查找的字符串。

请注意,您可以使用共同的快捷方式map(&:values).flatten而不是flat_map(&:values),这会产生相同的结果。

答案 2 :(得分:0)

如果您发布的主要原因是学习如何从散列数组中提取数据,那么您可以忽略此答案。

但是,如果您想要从数据库获取数据的最佳方式,我建议您使用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会为您执行此操作,并允许您添加其他查询,以便您可以在一个查询中收集所需的数据。

答案 3 :(得分:-1)

您可以使用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)

它会正常工作。