program story

Rails에서 동적 바인딩을 사용하여 원시 업데이트 SQL을 실행하는 방법

inputbox 2020. 9. 10. 07:49
반응형

Rails에서 동적 바인딩을 사용하여 원시 업데이트 SQL을 실행하는 방법


아래와 같이 하나의 업데이트 원시 SQL을 실행하고 싶습니다.

update table set f1=? where f2=? and f3=?

이 SQL은에 의해 실행 ActiveRecord::Base.connection.execute되지만 동적 매개 변수 값을 메서드에 전달하는 방법을 모르겠습니다.

누군가 내게 도움을 줄 수 있습니까?


Rails API가이를 일반적으로 수행하는 메소드를 노출하는 것처럼 보이지 않습니다. 기본 연결에 액세스하고 해당 방법을 사용해 볼 수 있습니다 (예 : MySQL의 경우).

st = ActiveRecord::Base.connection.raw_connection.prepare("update table set f1=? where f2=? and f3=?")
st.execute(f1, f2, f3)
st.close

이 작업을 수행하는 데 다른 영향이 있는지 확실하지 않습니다 (연결이 열린 상태로 유지 등). 실제 쿼리를 제외하고는 정상적인 업데이트를 위해 Rails 코드를 추적하여 수행하는 작업을 확인합니다.

준비된 쿼리를 사용하면 데이터베이스에서 약간의 시간을 절약 할 수 있지만이 작업을 연속으로 백만 번 수행하지 않는 한 일반적인 Ruby 대체로 업데이트를 빌드하는 것이 좋습니다.

ActiveRecord::Base.connection.execute("update table set f1=#{ActiveRecord::Base.sanitize(f1)}")

또는 댓글 작성자가 말한 것처럼 ActiveRecord를 사용하십시오.


ActiveRecord::Base.connectionquote문자열 값 (선택적으로 열 개체) 을받는 메서드가 있습니다. 따라서 다음과 같이 말할 수 있습니다.

ActiveRecord::Base.connection.execute(<<-EOQ)
  UPDATE  foo
  SET     bar = #{ActiveRecord::Base.connection.quote(baz)}
EOQ

Rails 마이그레이션 또는 ActiveRecord 객체에있는 경우 다음과 같이 단축 할 수 있습니다.

connection.execute(<<-EOQ)
  UPDATE  foo
  SET     bar = #{connection.quote(baz)}
EOQ

업데이트 : @kolen이 지적했듯이 exec_update대신 사용해야 합니다. 이것은 인용을 처리하고 메모리 누수를 방지합니다. 서명은 약간 다르게 작동합니다.

connection.exec_update(<<-EOQ, "SQL", [[nil, baz]])
  UPDATE  foo
  SET     bar = $1
EOQ

여기서 마지막 매개 변수는 바인드 매개 변수를 나타내는 튜플 배열입니다. 각 튜플에서 첫 번째 항목은 열 유형이고 두 번째 항목은 값입니다. nil열 유형에 대해 줄 수 있으며 Rails는 일반적으로 올바른 작업을 수행합니다.

이 또한 exec_query, exec_insert그리고 exec_delete당신이 필요에 따라.


다음과 같이 사용해야합니다.

YourModel.update_all(
  ActiveRecord::Base.send(:sanitize_sql_for_assignment, {:value => "'wow'"})
)

그것은 트릭을 할 것입니다. 은 Using 액티브 :: 자료 # 보내기 인보하는 방법을 sanitize_sql_for_assignment을 루비 (적어도 1.8.7 버전)는 사실 생략하게 sanitize_sql_for_assignment이 실제로 보호 방법입니다.


언젠가는 테이블 이름 대신 부모 클래스 이름을 사용하는 것이 좋습니다.

# Refers to the current class
self.class.unscoped.where(self.class.primary_key => id).update_all(created _at: timestamp)

예를 들어 "Person"기본 클래스, 하위 클래스 (및 데이터베이스 테이블) "Client"및 "Seller"대신 다음을 사용합니다.

Client.where(self.class.primary_key => id).update_all(created _at: timestamp)
Seller.where(self.class.primary_key => id).update_all(created _at: timestamp)

다음과 같이 기본 클래스의 객체를 사용할 수 있습니다.

person.class.unscoped.where(self.class.primary_key => id).update_all(created _at: timestamp)

이를 위해 원시 SQL을 사용하는 이유는 무엇입니까?

사용할 모델이있는 경우 where:

f1 = 'foo'
f2 = 'bar'
f3 = 'buzz'
YourModel.where('f1 = ? and f2 = ?', f1, f2).each do |ym|
  # or where(f1: f1, f2: f2).each do (...)
  ym.update(f3: f3) 
end

모델이없는 경우 (테이블 만) 상속 할 파일 및 모델을 만들 수 있습니다.ActiveRecord::Base

class YourTable < ActiveRecord::Base
  self.table_name = 'your_table' # specify explicitly if needed
end

다시 where위와 동일 하게 사용 하십시오.


activerecord 2.3.8과 함께 작동하도록 composite_primary_keys를 가져 오지 못했기 때문에 원시 SQL을 사용해야했습니다. 따라서 복합 기본 키를 사용하여 sqlserver 2000 테이블에 액세스하려면 원시 SQL이 필요했습니다.

sql = "update [db].[dbo].[#{Contacts.table_name}] " +
      "set [COLUMN] = 0 " +
      "where [CLIENT_ID] = '#{contact.CLIENT_ID}' and CONTACT_ID = '#{contact.CONTACT_ID}'"
st = ActiveRecord::Base.connection.raw_connection.prepare(sql)
st.execute

더 나은 솔루션을 사용할 수 있으면 공유하십시오.


Rails 3.1에서는 쿼리 인터페이스를 사용해야합니다.

  • new (속성)
  • 생성 (속성)
  • create! (속성)
  • 찾기 (id_or_array)
  • destroy (id_or_array)
  • destroy_all
  • delete(id_or_array)
  • delete_all
  • update(ids, updates)
  • update_all(updates)
  • exists?

update and update_all are the operation you need.

See details here: http://m.onkey.org/active-record-query-interface

참고URL : https://stackoverflow.com/questions/4483049/how-to-execute-a-raw-update-sql-with-dynamic-binding-in-rails

반응형