Rails raw SQL ejemplo


¿Cómo puedo convertir este código a sql crudo y usarlo en rails? Porque Cuando despliego este código en heroku, hay un error de tiempo de espera de solicitud.Creo que esto será más rápido si uso sql raw.

@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)
Author: Dorian, 2013-02-12

5 answers

Puedes hacer esto:

sql = "Select * from ... your sql query here"
records_array = ActiveRecord::Base.connection.execute(sql)

records_array entonces sería el resultado de su consulta sql en una matriz que puede iterar a través.

 313
Author: Huy,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-02-12 19:48:23

Sé que esto es viejo... Pero yo estaba teniendo el mismo problema hoy y encontrar una solución:

Model.find_by_sql

Si desea crear una instancia de los resultados:

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

Si quieres solo hash de valores:

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"}
]

Objeto de resultado:

select_all devuelve un objeto result. Puedes hacer cosas mágicas con él.

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

Fuentes:

  1. ActiveRecord-Findinig by SQL .
  2. Ruby on Rails-Resultado de Registro activo .
 127
Author: João Paulo Motta,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-06-17 20:14:58

Puede hacer direct SQL para tener una sola consulta para ambas tablas. Proporcionaré un ejemplo de consulta desinfectada para evitar que las personas coloquen variables directamente en la propia cadena (SQL injection danger), aunque este ejemplo no especificó la necesidad de hacerlo:

@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

Editar : como dijo Huy, una manera simple es ActiveRecord::Base.connection.execute("..."). Otra forma es ActiveRecord::Base.connection.exec_query('...').rows. Y puede usar declaraciones preparadas nativas, por ejemplo, si usa postgres, la declaración preparada se puede hacer con raw_connection, prepare y exec_prepared como se describe en https://stackoverflow.com/a/13806512/178651

También puede poner fragmentos SQL sin procesar en consultas relacionales de ActiveRecord: http://guides.rubyonrails.org/active_record_querying.html y en asociaciones, ámbitos, etc. Probablemente podría construir el mismo SQL con consultas relacionales de ActiveRecord y puede hacer cosas interesantes con ARel como Ernie menciona en http://erniemiller.org/2010/03/28/advanced-activerecord-3-queries-with-arel / . Y, por supuesto, hay otros Orm, joyas, etc.

Si esto se va a usar mucho y agregar índices no causará otros problemas de rendimiento/recursos, considere agregar un índice en la BASE de datos para payment_details.created_at y for payment_errors.created_at.

Si muchos registros y no todos los registros deben aparecer a la vez, considere usar paginación:

Si necesita paginar, considere crear una vista en la base de datos primero llamada payment_records que combine las tablas payment_details y payment_errors, luego tenga un modelo para la vista (que será de solo lectura). Algunos DBs admiten vistas materializadas, lo que podría ser una buena idea para el rendimiento.

También considere el hardware o especificaciones de VM en Rails server y DB server, configuración, espacio en disco, velocidad de red/latencia / etc., proximidad, etc. Y considere poner DB en un servidor/VM diferente a la aplicación Rails si no lo ha hecho, etc.

 24
Author: Gary S. Weaver,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-05-23 12:34:40

Puede ejecutar la consulta raw usando ActiveRecord. Y voy a sugerir para ir con bloque 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)
 16
Author: Deepak Mahakale,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-09-20 14:13:47

También puede mezclar SQL raw con condiciones ActiveRecord, por ejemplo, si desea llamar a una función en una condición:

my_instances = MyModel.where.not(attribute_a: nil) \
  .where('crc32(attribute_b) = ?', slot) \
  .select(:id)
 1
Author: tsauerwein,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-07-02 09:30:46