Rails 中的原始数据库查询
Posted
技术标签:
【中文标题】Rails 中的原始数据库查询【英文标题】:Raw DB querying in Rails 【发布时间】:2014-02-20 05:04:11 【问题描述】:我正在尝试在 rails 中运行以下原始查询,但发现它失败了:
query = 'SELECT * FROM users WHERE id IN ($1);'
results = ActiveRecord::Base.connection.exec_query(query, "My query", [ [1,2] ]);
我做错了什么?
我遇到的错误是这样开始的:
Could not log "sql.active_record" event. NoMethodError: undefined method `binary?' for 1:Fixnum
显然,我以某种方式滥用了[1, 2]
绑定参数,但我自己找不到合适的示例。
附:这是最小的失败示例,它源自一个更高级的查询,它不能转换为 ActiveRecord 调用链。换句话说,我在构建查询时不能依赖 Arel。
P.P.S.我正在使用rails 4.0.1
和postgresql 9.3
【问题讨论】:
我不确定 postgresql,因为我通常查询 mysql。但无论如何,语法应该是一样的。试试看:query = 'SELECT * FROM users WHERE id IN (?);'
results = ActiveRecord::Base.connection.exec_query(query, [1,2])
【参考方案1】:
我很确定您的 NoMethodError 来自日志记录。如果我们查看exec_query
,我们会看到:
def exec_query(sql, name = 'SQL', binds = [])
log(sql, name, binds) do
# call exec_no_cache(sql, binds) or exec_cache(sql, binds)...
如果我们查看exec_cache
,我们会看到:
def exec_cache(sql, binds)
#..
@connection.send_query_prepared(stmt_key, binds.map |col, val|
type_cast(val, col)
)
所以binds
应该是列/值对。 PostgreSQL 驱动程序期望col
是一个列对象,以便它可以询问它的名称是什么以及它应该如何格式化val
,该信息被exec_query
中的log
调用使用以产生漂亮的东西在 Rails 日志中可读。一些实验表明您可以将nil
用作col
,一切都很顺利。
这意味着我们已经开始这样做了:
exec_query(
'SELECT * FROM users WHERE id IN ($1)',
'my query',
[ [nil, [1,2]] ]
)
底层驱动程序可能知道也可能不知道如何处理[1,2]
数组,我只有Rails3 和PostgreSQL 扩展可供测试,它不喜欢[1,2]
。如果 Rails4 也不喜欢这个数组,那么你可以一个接一个地传递参数:
exec_query(
'SELECT * FROM users WHERE id IN ($1, $2)',
'my query',
[ [nil,1], [nil,2] ]
)
【讨论】:
【参考方案2】:我最近遇到了类似的问题。事实证明,在where in (?)
中,ActiveRecord 需要一个字符串,而不是一个数组。因此,您可以尝试传入一串以逗号分隔的 id,这应该可以解决问题。
【讨论】:
我也遇到了这个问题,但通过这样做解决了它:sql = "SELECT * FROM table_a WHERE identifier IN (?)"
where_equals = ["id_1", "id_2"]
ActiveRecord::Base.connection.exec_query(ActiveRecord::Base.send(:sanitize_sql_array, [sql, where_equals]))
(?)
语法起初对我不起作用。我切换到使用备用 '%s'
语法,然后最终使用哈希语法。 e.g. sanitize_sql_array(["name=:name and group_id=:group_id", name: "foo'bar", group_id: 4]) # => "name='foo''bar' and group_id=4" sanitize_sql_array(["name='%s' and group_id='%s'", "foo'bar", 4]) # => "name='foo''bar' and group_id='4'"
来自api.rubyonrails.org/classes/ActiveRecord/Sanitization/…以上是关于Rails 中的原始数据库查询的主要内容,如果未能解决你的问题,请参考以下文章