293

このコードを生のSQLに変換してレールで使用するにはどうすればよいですか? このコードをherokuにデプロイすると、リクエストのタイムアウトエラーが発生するため、生の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)
4

6 に答える 6

519

あなたはこれを行うことができます:

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

records_array次に、反復できる配列内のSQLクエリの結果になります。

于 2013-02-12T19:48:23.317 に答える
227

私はこれが古いことを知っています...しかし、私は今日同じ問題を抱えていて、解決策を見つけました:

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 - アクティブ レコードの結果
于 2015-01-16T18:33:51.447 に答える
38

を使用して生のクエリを実行できます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)
于 2016-09-20T14:13:47.007 に答える
30

直接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

編集:Huyが言ったように、簡単な方法はActiveRecord::Base.connection.execute("...")です。別の方法はActiveRecord::Base.connection.exec_query('...').rowsです。また、ネイティブのプリペアドステートメントを使用できます。たとえば、postgresを使用する場合、 https: //stackoverflow.com/a/13806512/178651で説明されているように、プリペアドステートメントはraw_connection、prepare、およびexec_preparedで実行できます。

生のSQLフラグメントをActiveRecordリレーショナルクエリに入れることもできます:http://guides.rubyonrails.org/active_record_querying.html そしてアソシエーション、スコープなど。おそらくActiveRecordリレーショナルクエリで同じSQLを構築でき、アーニーがhttp://erniemiller.org/2010/03/28/advanced-activerecord-3-queries-with-arel/で言及しているARel 。そしてもちろん、他のORM、宝石などもあります。

これが頻繁に使用され、インデックスを追加しても他のパフォーマンス/リソースの問題が発生しない場合は、DBにpayment_details.created_atおよびpayment_errors.created_atのインデックスを追加することを検討してください。

一度に多くのレコードを表示する必要があり、すべてのレコードを表示する必要がない場合は、ページネーションの使用を検討してください。

ページ付けが必要な場合は、最初にpayment_recordsという名前のビューをDBに作成し、payment_detailsテーブルとpayment_errorsテーブルを組み合わせてから、ビューのモデル(読み取り専用)を作成することを検討してください。一部のDBはマテリアライズド・ビューをサポートしています。これはパフォーマンスにとって良い考えかもしれません。

RailsサーバーとDBサーバーのハードウェアまたはVMの仕様、構成、ディスクスペース、ネットワーク速度/遅延など、近接性なども考慮してください。そうでない場合は、Railsアプリとは異なるサーバー/VMにDBを配置することを検討してください。 。

于 2013-02-12T18:39:33.180 に答える