web-dev-qa-db-ja.com

生のSQLのRailsの例

このコードを生の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)
203
Johnny Cash

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

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

records_arrayはそれからあなたが繰り返すことができる配列の中のあなたのSQLクエリの結果であるでしょう。

367
Huy

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

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_allresultオブジェクトを返します。あなたはそれで魔法のことをすることができます。

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 - アクティブレコードの結果
148

両方のテーブルに対して単一のクエリを持つように直接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を構築でき、Ernieが http://erniemiller.org/2010/3/28/advanced-activerecord-で述べているように、ARelを使ってクールなことを実行できます。 3つのクエリでarel / 。そしてもちろん、他にもORM、宝石などがあります。

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

すべてのレコードではなく大量のレコードを一度に表示する必要がある場合は、ページ区切りの使用を検討してください。

ページ分割する必要がある場合は、最初にpayment_detailsテーブルとpayment_errorsテーブルを組み合わせた、payment_recordsという名前のビューをDBに作成してから、ビューのモデルを作成します(これは読み取り専用になります)。一部のDBでは、マテリアライズドビューがサポートされています。これは、パフォーマンスを向上させる上で役立ちます。

また、RailsサーバーとDBサーバーのハードウェアやVMの仕様、設定、ディスク容量、ネットワーク速度/待ち時間など、近接性なども検討してください。あなたは持っていない、など.

25
Gary S. Weaver

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)
21
Deepak Mahakale

たとえば、条件内で関数を呼び出したい場合は、生のSQLとActiveRecordの条件を組み合わせることもできます。

my_instances = MyModel.where.not(attribute_a: nil) \
  .where('crc32(attribute_b) = ?', slot) \
  .select(:id)
0
tsauerwein

ActiveRecordクラスのexec_queryを使って作業したいのですが、それはクエリーをオブジェクトに変換するマッピングを返すので、サブジェクトが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"]
0