在Rails中进行原始的数据库查询

20

我试图在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。

另外:rails 4.0.1postgresql 9.3被使用。


1
我对PostgreSQL不太确定,因为我通常查询MySQL。但无论如何,语法应该是相同的。尝试:query = 'SELECT * FROM users WHERE id IN (?);'results = ActiveRecord::Base.connection.exec_query(query, [1,2]) - Utsav Kesharwani
2个回答

17

我很确定你的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字符串,这应该就可以解决问题了。


2
我也遇到了这个问题,但是通过以下方法解决了它: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])) - saywhatnow
一开始,(?) 语法对我不起作用。我转而使用备用的 '%s' 语法,最终使用了哈希语法。例如: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'"

来源:https://api.rubyonrails.org/classes/ActiveRecord/Sanitization/ClassMethods.html#method-i-sanitize_sql_array
- Stefan Lyew

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接