[英]How to pass array as bind variable to Rails/ActiveRecord raw SQL queries?
I need to pass an array of ids into my raw sql query like this: 我需要像这样将ID数组传递到我的原始sql查询中:
select offers.* from offers where id in (1,2,3,4,5)
The real query includes a lot of joins and aggregation functions and can't be written using Arel expressions or ActiveRecord model methods like Offer.where(id: [...])
. 真正的查询包含许多联接和聚合函数,不能使用Arel表达式或ActiveRecord模型方法(如
Offer.where(id: [...])
。 I'm looking exactly for how to use bind variables in raw queries. 我正在寻找如何在原始查询中使用绑定变量。
Instead of interpolating ids into string I want to use bind variables like this (pseudo-code): 与其将id内插到字符串中,不如使用绑定变量(伪代码):
ActiveRecord::Base.connection.select_all("select offers.* from offers where id in (:ids)", {ids: [1,2,3,4,5]})
However, I can't find any solution to perform this. 但是,我找不到任何解决方案来执行此操作。 From this ticket I've got a comment with related test-case in ActiveRecord code with the following example:
从这张票证中,我得到了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)
I've tried this approach, but it didn't worked at all, my "?" 我已经尝试过这种方法,但是根本没有用,我的“?” was not replaced by actual values.
没有被实际值代替。
I'm using Rails 5.1.6 and MariaDB database. 我正在使用Rails 5.1.6和MariaDB数据库。
You could do this in a much simpler fashion purely with arel
. 您完全可以使用
arel
来以更简单的方式执行此arel
。 (Also it makes the code far more maintainable than SQL strings) (这也使代码比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)
This will result in the following SQL 这将导致以下SQL
SELECT
[offers].*
FROM
[offers]
WHERE
[offers].[id] IN (1,2,3,4,5)
When executed you will receive an ActiveRecord::Result
object with is usually easiest to deal with by calling to_hash
and each resulting row will be turned into a Hash
of {column_name => value}
执行后,您将收到一个
ActiveRecord::Result
对象,通常最容易通过调用to_hash
进行处理,并且每个结果行都将被转换为{column_name => value}
的Hash
However if you are using rails and Offer
is a true model then: 但是,如果您使用的是Rails,并且
Offer
是真实的模型,则:
Offer.where(id: ids)
Will result in the same query and will return an ActiveRecord::Relation
collection of Offer
objects which is generally more preferable. 将导致相同的查询,并将返回
Offer
对象的ActiveRecord::Relation
集合,通常更可取。
Update 更新
Seems like you need to enable prepared_statements
in mysql2 ( mariadb
) in order to use the bind params, which can be done like this: 好像你需要启用
prepared_statements
在mysql2( mariadb
,以使用绑定参数,可以它可以这样做):
default: &default
adapter: mysql2
encoding: utf8
prepared_statements: true # <- here we go!
Please note the following pieces of code: 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/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/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/abstract_adapter.rb#L630
https://github.com/rails/rails/blob/5-1-stable/activerecord/lib/active_record/connection_adapters/mysql/database_statements.rb#L30 https://github.com/rails/rails/blob/5-1-stable/activerecord/lib/active_record/connection_adapters/mysql/database_statements.rb#L30
As you can see in the last code exec_query
ignores bind_params
if prepared_statements
is turned off (which appears to be the default for the mysql2
adapter). 正如你可以在最后的代码中看到
exec_query
忽略bind_params
如果prepared_statements
被关闭(这似乎是在默认mysql2
适配器)。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.