Запрос Raw DB в 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]
привязывать параметры как-то, но сам не смог найти правильный пример.
P.S. Это минимальный неудачный пример, полученный из гораздо более продвинутого запроса, который не может быть превращен в цепочку вызовов ActiveRecord. Другими словами - я не могу полагаться на Ареля при построении моего запроса.
P.P.S. Я использую rails 4.0.1
и postgresql 9.3
Ответы
Ответ 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
, эта информация используется вызовом log
в exec_query
для создания чего-то довольно и читаемый человеком в журналах 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 ожидает строку, а не массив. Поэтому вы можете попробовать передать строку с идентификаторами, разделенными запятыми, и это должно сделать трюк.
Ответ 3
Я не понимаю, почему вы не просто создаете строку запроса с интерполяцией внутри нее:
id_list = [1,3,5,7,9,13]
# use .join to create a string from the id_list using a comma inbetween each one
query = "SELECT * FROM users WHERE id IN (#{id_list.join(', ')})"
# query = "SELECT * FROM users WHERE id IN (1, 3, 5, 7, 9, 13)"
results = ActiveRecord::Base.connection.exec_query(query)