如何通过数组作为绑定变量的Rails / ActiveRecord的原始的SQL查询?

问题描述 投票:0回答:1

我需要一个ID数组传递到我的原始的SQL查询是这样的:

select offers.* from offers where id in (1,2,3,4,5)

真正的查询包括大量的连接和聚合功能,并且不能使用阿雷尔表达式或类似Offer.where(id: [...]) ActiveRecord的模型方法来写。我在寻找确切地了解如何在原始查询中使用绑定变量。

相反,内插ID添加到字符串我想使用绑定变量是这样的(伪代码):

ActiveRecord::Base.connection.select_all("select offers.* from offers where id in (:ids)", {ids: [1,2,3,4,5]})

但是,我找不到任何解决方案来执行此。从this票我得在与following例如ActiveRecord的代码相关的测试用例评论:

sub   = Arel::Nodes::BindParam.new
binds = [Relation::QueryAttribute.new("id", 1, Type::Value.new)]
sql   = "select * from topics where id = #{sub.to_sql}"

@connection.exec_query(sql, "SQL", binds)

我试过这种方法,但它没有工作可言,我的“?”没有实际值替换。

我使用Rails 5.1.6和MariaDB的数据库。

ruby-on-rails activerecord
1个回答
0
投票

你可以在一个更简单的方式与arel这样做纯粹。 (此外,它使得代码更易于维护比SQL字符串)

offers = Arel::Table.new('offers') 
ids = [1,2,3,4,5]
query = offers.project(Arel.star).where(offers[:id].in(ids))
ActiveRecord::Base.connection.exec_query(query.to_sql)

这将导致以下SQL

SELECT 
  [offers].*
FROM 
  [offers]
WHERE 
  [offers].[id] IN (1,2,3,4,5)

当执行与通常是最容易通过调用ActiveRecord::Result应对每生成的行会变成to_hashHash您将收到{column_name => value}对象

但是,如果您使用的是轨道和Offer是一个真正的模型,则:

Offer.where(id: ids)

将导致相同的查询,并且将返回ActiveRecord::Relation对象的Offer集合通常更理想是。

更新

好像你需要启用prepared_statements中才能使用绑定参数,可以它可以这样做mysql2(mariadb):

default: &default
  adapter: mysql2
  encoding: utf8
  prepared_statements: true  # <- here we go!

请注意以下的代码段:https://github.com/rails/rails/blob/5-1-stable/activerecord/lib/active_record/connection_adapters/abstract_adapter.rb#L115

https://github.com/rails/rails/blob/5-1-stable/activerecord/lib/active_record/connection_adapters/mysql2_adapter.rb#L40

https://github.com/rails/rails/blob/5-1-stable/activerecord/lib/active_record/connection_adapters/abstract_adapter.rb#L630

https://github.com/rails/rails/blob/5-1-stable/activerecord/lib/active_record/connection_adapters/mysql/database_statements.rb#L30

正如你在上次的代码exec_query忽略bind_params如果prepared_statements被关闭(这似乎是为mysql2适配器默认)看到。

© www.soinside.com 2019 - 2024. All rights reserved.