Пример Rails raw SQL
Как я могу преобразовать этот код в raw sql и использовать в rails? Потому что, когда я внедряю этот код в heroku, возникает ошибка тайм-аута запроса. Я думаю, что это будет быстрее, если я использую raw sql.
@payments = PaymentDetail.joins(:project).order('payment_details.created_at desc')
@payment_errors = PaymentError.joins(:project).order('payment_errors.created_at desc')
@all_payments = (@payments + @payment_errors)
5 ответов
Вы можете сделать это:
sql = "Select * from ... your sql query here"
records_array = ActiveRecord::Base.connection.execute(sql)
records_array
будет тогда результатом вашего sql-запроса в массиве, который вы можете перебрать.
Я знаю, что это старый... Но у меня была та же проблема сегодня и найти решение:
Model.find_by_sql
Если вы хотите создать экземпляр результатов:
Client.find_by_sql("
SELECT * FROM clients
INNER JOIN orders ON clients.id = orders.client_id
ORDER BY clients.created_at desc
")
# => [<Client id: 1, first_name: "Lucas" >, <Client id: 2, first_name: "Jan">...]
Model.connection.select_all('sql').to_hash
Если вы хотите просто хэш значений:
Client.connection.select_all("SELECT first_name, created_at FROM clients
WHERE id = '1'").to_hash
# => [
{"first_name"=>"Rafael", "created_at"=>"2012-11-10 23:23:45.281189"},
{"first_name"=>"Eileen", "created_at"=>"2013-12-09 11:22:35.221282"}
]
Объект результата:
select_all
возвращает result
объект. Вы можете делать магические вещи с ним.
result = Post.connection.select_all('SELECT id, title, body FROM posts')
# Get the column names of the result:
result.columns
# => ["id", "title", "body"]
# Get the record values of the result:
result.rows
# => [[1, "title_1", "body_1"],
[2, "title_2", "body_2"],
...
]
# Get an array of hashes representing the result (column => value):
result.to_hash
# => [{"id" => 1, "title" => "title_1", "body" => "body_1"},
{"id" => 2, "title" => "title_2", "body" => "body_2"},
...
]
# ActiveRecord::Result also includes Enumerable.
result.each do |row|
puts row['title'] + " " + row['body']
end
Источники:
Вы можете выполнить необработанный запрос, используя ActiveRecord
, И я предложу пойти с блоком SQL
query = <<-SQL
SELECT *
FROM payment_details
INNER JOIN projects
ON projects.id = payment_details.project_id
ORDER BY payment_details.created_at DESC
SQL
result = ActiveRecord::Base.connection.execute(query)
Вы можете сделать прямой SQL, чтобы иметь один запрос для обеих таблиц. Я приведу пример очищенного запроса, который, как мы надеемся, не позволит людям помещать переменные непосредственно в саму строку (опасность внедрения SQL), даже если в этом примере не указана необходимость этого:
@results = []
ActiveRecord::Base.connection.select_all(
ActiveRecord::Base.send(:sanitize_sql_array,
["... your SQL query goes here and ?, ?, ? are replaced...;", a, b, c])
).each do |record|
# instead of an array of hashes, you could put in a custom object with attributes
@results << {col_a_name: record["col_a_name"], col_b_name: record["col_b_name"], ...}
end
Редактировать: как сказал Хай, простой способ ActiveRecord::Base.connection.execute("...")
, Другой способ ActiveRecord::Base.connection.exec_query('...').rows
, И вы можете использовать собственные подготовленные операторы, например, если вы используете postgres, подготовленные операторы можно сделать с помощью raw_connection, prepare и exec_prepared, как описано в /questions/16249788/podgotovlennoe-zayavlenie-o-postgresql-v-rails/16249798#16249798
Вы также можете помещать необработанные фрагменты SQL в реляционные запросы ActiveRecord: http://guides.rubyonrails.org/active_record_querying.html а также в ассоциации, области и т. Д. Скорее всего, вы можете создать тот же SQL с помощью реляционных запросов ActiveRecord и делать крутые вещи с ARel, как упоминает Эрни в http://erniemiller.org/2010/03/28/advanced-activerecord-3-queries-with-arel/. И, конечно же, есть другие ORM, драгоценные камни и т. Д.
Если это будет использоваться часто, и добавление индексов не вызовет других проблем с производительностью / ресурсами, рассмотрите возможность добавления индекса в БД для payment_details.created_at и для payment_errors.created_at.
Если нужно показать сразу много записей, а не все записи, рассмотрите возможность использования нумерации страниц:
Если вам нужно разбить на страницы, рассмотрите возможность создания представления в БД, которое сначала называется payment_records, которое объединяет таблицы payment_details и payment_errors, а затем создайте модель для представления (которое будет доступно только для чтения). Некоторые БД поддерживают материализованные представления, что может быть хорошей идеей для производительности.
Также рассмотрите спецификации оборудования или ВМ на сервере Rails и сервере БД, конфигурацию, дисковое пространство, скорость / задержку в сети и т. Д., Близость и т. Д. И рассмотрите возможность размещения БД на другом сервере / ВМ, чем приложение Rails, если у вас его нет, и т. Д.,
Я хочу работать с exec_query
из ActiveRecord
class, потому что он возвращает отображение запроса, трансформирующегося в объект, поэтому он становится очень практичным и продуктивным для итерации с объектами, когда объектом является Raw SQL.
Пример:
values = ActiveRecord::Base.connection.exec_query("select * from clients")
p values
и вернуть этот полный запрос:
[{"id": 1, "name": "user 1"}, {"id": 2, "name": "user 2"}, {"id": 3, "name": "user 3"}]
Получить только список значений
p values.rows
[[1, "user 1"], [2, "user 2"], [3, "user 3"]]
Получить только поля столбцов
p values.columns
["id", "name"]
Вы также можете смешивать сырой SQL с условиями ActiveRecord, например, если вы хотите вызвать функцию в условии:
my_instances = MyModel.where.not(attribute_a: nil) \
.where('crc32(attribute_b) = ?', slot) \
.select(:id)