[ruby-on-rails] Rails 마이그레이션에서 한 열을 다른 열의 값으로 업데이트

저는 Rails 앱에 수십만 개의 레코드가있는 테이블이 있으며 created_at타임 스탬프 만 있습니다 . 이 레코드를 편집하는 기능을 추가하고 있으므로 updated_at테이블에 타임 스탬프를 추가하려고 합니다. 열을 추가하기 위해 마이그레이션 할 때 Rails에서 새로 생성 된 행의 기본값이기 때문에 모든 행을 업데이트하여 새 행 updated_at과 이전을 일치시키고 싶습니다 created_at. a를 수행 find(:all)하고 레코드를 반복 할 수 있지만 테이블 크기 때문에 몇 시간이 걸립니다. 내가 정말로하고 싶은 것은 :

UPDATE table_name SET updated_at = created_at;

원시 SQL을 실행하는 대신 ActiveRecord를 사용하여 Rails 마이그레이션을 수행하는 더 좋은 방법이 있습니까?



답변

마이그레이션을 만들 것입니다.

rails g migration set_updated_at_values

그리고 그 안에 다음과 같이 작성하십시오.

class SetUpdatedAt < ActiveRecord::Migration
  def self.up
    Yourmodel.update_all("updated_at=created_at")
  end

  def self.down
  end
end

이렇게하면 두 가지를 달성 할 수 있습니다.

  • 이는 가능한 각 배포 (필요한 경우)가 실행되는 반복 가능한 프로세스입니다.
  • 이것은 효율적입니다. 나는 더 많은 루비 스크 솔루션을 생각할 수 없습니다 (효율적입니다).

참고 : activerecord를 사용하여 쿼리를 작성하기가 너무 어려워지면 마이그레이션 내에서 원시 SQL을 실행할 수도 있습니다. 다음을 작성하십시오.

Yourmodel.connection.execute("update your_models set ... <complicated query> ...")


답변

raw SQL과 매우 유사하게 작동 하는 update_all 을 사용할 수 있습니다 . 그것이 당신이 가진 모든 옵션입니다.

BTW 개인적으로 나는 마이그레이션에 그다지 관심을 기울이지 않습니다. 때로는 원시 SQL이 정말 최상의 솔루션입니다. 일반적으로 마이그레이션 코드는 재사용되지 않습니다. 이것은 일회성 작업이므로 코드 순도에 대해서는 신경 쓰지 않습니다.


답변

gregdan이 썼 듯이 update_all. 다음과 같이 할 수 있습니다.

Model.where(...).update_all('updated_at = created_at')

첫 번째 부분은 일반적인 조건 세트입니다. 마지막 부분은 할당 방법을 설명합니다. 이것은 UPDATE최소한 Rails 4에서 성명서 를 생성합니다 .


답변

다음 명령을 직접 실행할 수 있습니다. rails console
ActiveRecord::Base.connection.execute("UPDATE TABLE_NAME SET COL2 = COL1")

예 : 항목 테이블의 remote_id로 항목 테이블의 sku를 업데이트하고 싶습니다. 명령은 다음과 같습니다.
ActiveRecord::Base.connection.execute("UPDATE items SET sku = remote_id")


답변

이것은 질의가 위험에 노출되기 때문에 질의를 작성할 필요없이 일반적인 해결 방법입니다.

  class Demo < ActiveRecord::Migration
    def change
     add_column :events, :time_zone, :string
     Test.all.each do |p|
       p.update_attributes(time_zone: p.check.last.time_zone)
     end
     remove_column :sessions, :time_zone
    end
  end


답변

일회성 작업으로 rails console. 정말 몇 시간이 걸릴까요? 수백만 개의 레코드가 있다면 …

records = ModelName.all; records do |r|; r.update_attributes(:updated_at => r.created_at); r.save!; end;`


답변