3

유형이 부울 인 Active 열이있는 사용자라는 테이블이 있습니다. 곧 그 열의 유형을 문자열로 변경해야 할 것입니다. Active의 열 값을 모두 true에서 active로 변경하고 false에서 "inactive"로 변경해야합니다. 레일이 열 유형을 변경하고 열 값을 업데이트합니다.

는 유형 변경을 중단하지 않도록 내가 Change a column type from Date to DateTime during ROR migration

class ChangeColumnTypeInUsers < ActiveRecord::Migration 
    def up 
    change_column :users, :active, :string 
    end 

    def down 
    change_column :users, :active, :boolean 
    end 
end 

가 어떻게 열 값을 업데이트 할 때 사용하는 열 유형을 변경하려면? 자동으로 변환됩니까? true로 설정하면 true입니까?

답변

2

당신은 그것을 할 수있는 USING clause of ALTER TABLE :

옵션 USING 절은 오래된에서 새 열 값을 계산하는 방법을 지정합니다; 생략하면 기본 변환은 이전 데이터 유형에서 new 로의 배역 캐스팅과 동일합니다. 간단한 SQL 유형 캐스트가 문자열 'true''false' 당신을 떠날 것이다

그래서 당신은 사용을 추가 할 수 없습니다. 나는 AR을 무시하고 손으로 그것을 할 것 :

connection.execute(%q{ 
    alter table users 
    alter column active 
    type text 
    using case when active then 'active' else 'inactive' end 
}) 

당신을위한 중요한 부분은 마지막에 using case ... 부분입니다. 당신은 옳은 일을에 AR을 속여 일반적인 AR 틱 change_column 물건과 함께 그것을 사용할 수 있습니다 : 나는 열 유형으로 text을 사용하고

class ChangeColumnTypeInUsers < ActiveRecord::Migration 
    def up 
    change_column :users, :active, "text using case when active then 'active' else 'inactive' end" 
    end 

    def down 
    change_column :users, :active, "boolean using active = 'active'" 
    end 
end 

참고. 레일스는 :string에 제한이 없다고 말할 때 데이터베이스 내부에 varchar(255)을 사용합니다. PostgreSQL에서는 모든 문자열 유형 pretty much the same internally에 대한 저장소를 처리하기 때문에 무의미하며 char(n)varchar(n)의 길이 제한은 실제로 text보다 비쌉니다. 그렇다면 :string은 PostgreSQL에서 의미가 있습니다. 특정 :limit을 포함해야하는 경우입니다 (길이가 CHECKtext 열이 더 적합 할 수 있지만 AR은 너무 바보이어서 CHECK과 같은 고급 항목에 대해 알 수 없습니다) 제약 조건).

+0

나는 당신의 AR-ish 솔루션을 마이그레이션으로 돌렸고, 올바른 일을했다. 철저한 설명에 감사드립니다! – MicFin

+0

당신이 sqlite에서 이것을 실행하면 어떤 일이 일어날 지 궁금합니다. Postgres를 위해 매우 우아하게 보입니다! 좋은 물건 – DevDude

+0

@DevDude : 아마도 넘어져서 불이 났을 것입니다. 그러나 SQLite로 개발하고 PostgreSQL에 배치하면 고통과 고통과 같은 가치를 얻을 수 있습니다. ActiveRecord가 데이터베이스 이식성을 제공 할 것으로 기대하고 있다면 슬프게도 오인됩니다. 그런 식으로 작동하지 않습니다. –

3

부울 : 활성 열의 이름을 바꾸면 쉽게 마이그레이션 할 수 있습니다. 새 열을 추가하십시오. SQL 업데이트를 실행 한 다음 사용하지 않은 열을 제거하십시오. 동일한 마이그레이션에서 모두 수행 할 수 있습니다. 이렇게 아래로 이동은 포함되지 않으므로 자신의 위험에 따라 사용하십시오.

class ChangeColumnTypeInUsers < ActiveRecord::Migration 
    def up 
    rename_column :users, :active, :active_boolean 
    add_column :users, :active, :string 
    execute "UPDATE users SET active = 'true' WHERE active_boolean = true" 
    execute "UPDATE users SET active = 'inactive' WHERE active_boolean = false" 
    remove_column :users, :active_boolean 
    end 
end 
+1

주의 사항 : postgresql (특별히 명시하지는 않지만 postgresql을 사용하여 태그를 지정한 경우)의 값은 "true"및 "false"가 아닌 "t"및 "f"로 설정 될 수 있습니다. MicFin - SQL 콘솔에서 "사용자와 별개의 활성 사용자 선택"을 수행하여 실제 값이 무엇인지 확인합니다.그런 다음 @DevDude가 제안한 답변을 –

+1

@MaxWilliams와 같이 사용할 수 있습니다. PostgreSQL은 기본 '부울'유형을 가지고 있으며 'true', 'false','t '및'f '를 사용할 수 있습니다. '문자 그대로의 부울 들로서 이것은 괜찮습니다. 그러나 이것은 필요한 것보다 훨씬 더 많은 작업입니다. 방향 비교 대신 active_boolean과 where not active_boolean을 사용하면 CASE 표현식을 사용하는 UPDATE 하나면 충분하며, UPDATE 권한을 USING 절을 추가하여 ALTER TABLE. –

+0

이 답변은 잘 작동하는 것 같지만 @ muistooshort의 대답은 간단하고 안전합니다 (아래 포함). 이것이 정답이어야하는 이유에 대해 제가 빠진 것이 있다면 알려주십시오. – MicFin

0

내가하지 않은,하지만 난 단지 당신의 위로 방법에 더 추가하거나 위쪽 부분을 처리하기 위해 별도의 마이그레이션을 쓰고 생각합니다. 그런 ...

class ChangeColumnTypeInUsers < ActiveRecord::Migration 
    def up 
    change_column :users, :active, :string 

    User.find_each do |user| 
     user.active = "active" if user.active = true 
     user.save! 
    end 
    end 

    def down 
    change_column :users, :active, :boolean 
    end 
end 

false도 처리 할 수 ​​있습니다. 일해야한다. 난 그냥 내 데이터베이스에서 단일 사용자 콘솔에 그것을 테스트, 잘 보인다. 하나는 아주 쉽게 사용하여 이동에

+0

Art, 나는 다음과 같은 이유 때문에 마이그레이션과 같은 모델을 만지면 매우 조심 스러울 것입니다. 모델을 업데이트하면 모든 종류의 예상치 못한 문제를 일으킬 수있는 Active Record Callback이 트리거됩니다. 즉 Observers to 화재 등이 접근법과 조심해! – DevDude

+0

코멘트 주셔서 감사합니다. 저는 여전히 레일스 멍청이이고 항상 모든 항목이 어떻게 어울리는 지 항상 확신하지 못합니다. 이런 조언은 시간 내 주셔서 감사합니다. 위의 옵션이 내 것보다 더 완벽하다고 생각하므로 어쨌든 더 나은 대답입니다 :). – Art

관련 문제