Пример 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

Источники:

  1. ActiveRecord - поиск по SQL.
  2. Ruby on Rails - результат активной записи.

Вы можете выполнить необработанный запрос, используя 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)
Другие вопросы по тегам