[sql] 레일스 원시 SQL 예제

이 코드를 원시 SQL로 변환하고 레일에서 사용하려면 어떻게해야합니까? 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)



답변

당신은 이것을 할 수 있습니다 :

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_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. SQL에 의한 ActiveRecord-Findinig .
  2. Ruby on Rails-Active 레코드 결과
    .

답변

을 사용하여 원시 쿼리를 실행할 수 있습니다 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

편집 : Huy가 말했듯이 간단한 방법은 ActiveRecord::Base.connection.execute("...")입니다. 다른 방법은 ActiveRecord::Base.connection.exec_query('...').rows입니다. 포스트 그레스를 사용하는 경우 그리고 당신은 예를 들어, 기본 준비된 문을 사용하여 준비된 문을 준비 raw_connection 수행 할 수 있습니다, 그리고에 설명 된대로 exec_prepared https://stackoverflow.com/a/13806512/178651

또한 원시 SQL 조각을 ActiveRecord 관계형 쿼리 ( http://guides.rubyonrails.org/active_record_querying.html)
및 연관, 범위 등으로 넣을 수 있습니다. ActiveRecord 관계형 쿼리를 사용하여 동일한 SQL을 구성 할 수 있습니다. Ernie가 http://erniemiller.org/2010/03/28/advanced-activerecord-3-queries-with-arel/ 에서 언급 한 ARel . 물론 다른 ORM, 보석 등도 있습니다.

이것이 많이 사용될 것이며 인덱스를 추가해도 다른 성능 / 자원 문제가 발생하지 않으면 payment_details.created_at 및 payment_errors.created_at에 대한 인덱스를 DB에 추가하십시오.

많은 레코드가 있고 모든 레코드가 한 번에 나타나지 않아도되는 경우 페이지 매김 사용을 고려하십시오.

페이지를 매길 필요가있는 경우, payment_details 및 payment_errors 테이블을 결합한 payment_records라는 뷰를 DB에 먼저 작성한 다음 뷰에 대한 모델 (읽기 전용)을 작성하십시오. 일부 DB는 구체화 된 뷰를 지원하므로 성능에 좋습니다.

또한 Rails 서버 및 DB 서버, 구성, 디스크 공간, 네트워크 속도 / 대기 시간 등의 하드웨어 또는 VM 사양, 근접성 등을 고려하고 그렇지 않은 경우 Rails 앱과 다른 서버 / VM에 DB를 배치하는 것을 고려하십시오. .


답변

나는 작업 할 exec_queryActiveRecord이 객체로 변신 쿼리의 매핑을 반환하기 때문에 피사체가 원시 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)


답변