2013-06-12 42 views
44

Tôi đã google'd aroung một chút và dường như không có câu trả lời thỏa mãn cho vấn đề của tôi.Di chuyển đường ray - change_column với loại chuyển đổi

Tôi có một bảng có cột kiểu chuỗi. Tôi muốn chạy sau di cư:

class ChangeColumnToBoolean < ActiveRecord::Migration 
    def up 
     change_column :users, :smoking, :boolean 
    end 
end 

Khi tôi chạy này tôi nhận được lỗi sau

PG::Error: ERROR: column "smoking" cannot be cast automatically to type boolean 
HINT: Specify a USING expression to perform the conversion. 
: ALTER TABLE "users" ALTER COLUMN "smoking" TYPE boolean 

Tôi biết tôi có thể thực hiện chuyển đổi này sử dụng SQL tinh khiết nhưng vẫn nó sẽ đẹp hơn nếu tôi có thể làm điều đó với Rails. Tôi đã đi qua mã Rails và dường như theres không có khả năng như vậy, nhưng có lẽ ai đó biết một cách?

Tôi không quan tâm đến: - tinh khiết SQL - thả các cột - tạo cột khác, chuyển đổi dữ liệu, thả ban đầu và sau đó đổi tên

+0

Nhưng đó là cách duy nhất như xa như tôi biết .. bạn phải tạo cột, di chuyển và loại bỏ cũ cột ... – ZedTuX

Trả lời

5

Vì tôi đang sử dụng Postgres, tôi đã đi với giải pháp SQL ngay bây giờ. Query sử dụng:

execute 'ALTER TABLE "users" ALTER COLUMN "smoking" TYPE boolean USING CASE WHEN "flatshare"=\'true\' THEN \'t\'::boolean ELSE \'f\'::boolean END' 

Nó chỉ hoạt động nếu người ta có một lĩnh vực đầy đúng/chuỗi sai (như đài phát thanh mặc định bộ sưu tập nút helper với buộc kiểu boolean sẽ tạo ra)

+0

Điều này là xấu vì bất cứ khi nào bạn xây dựng lại DB của bạn, bạn sẽ phải chạy lại câu lệnh SQL này. –

+1

@DonnyP nếu tôi đặt nó trong di chuyển? Srsly? –

+1

@DonnyP nếu bằng cách "xây dựng lại cơ sở dữ liệu", bạn có nghĩa là "xây dựng lại lược đồ cơ sở dữ liệu" - cách được khuyến nghị để thực hiện điều này là thông qua 'rake db: structure: load' /' rake db: schema: load' và không chạy tất cả các di chuyển. –

34

Không phải tất cả cơ sở dữ liệu cho phép thay đổi kiểu cột, thường lấy phương pháp tiếp cận là thêm cột mới của loại mong muốn, mang bất kỳ dữ liệu nào qua, xóa cột cũ và đổi tên cột mới.

add_column :users, :smoking_tmp, :boolean 

User.reset_column_information # make the new column available to model methods 
User.all.each do |user| 
    user.smoking_tmp = user.smoking == 1 ? true : false # If smoking was an int, for example 
    user.save 
end 

# OR as an update all call, set a default of false on the new column then update all to true if appropriate. 
User.where(:smoking => 1).update_all(:smoking_tmp = true) 

remove_column :users, :smoking 
rename_column :users, :smoking_tmp, :smoking 
+0

Vâng, đó là một giải pháp, nhưng như tôi đã nói, không phải là một trong những tôi đang tìm kiếm. Ngoài ra nó là xấu xa về tốc độ - trên một cơ sở dữ liệu sản xuất lớn, nó sẽ mất nhiều thời gian để chạy. –

+1

@ MichałSzyndel Bạn có thể sử dụng [update_all] (http: // apidock.com/rails/ActiveRecord/Relation/update_all) thay vì khối sẽ chỉ tạo ra một câu lệnh SQL. Đã thêm ví dụ. – Matt

+0

Ngoài ra, bạn có thể sử dụng 'user.smoking.to_boolean' nếu bạn có các chuỗi như" Có "và" Không "trong cột gốc, không phải là boolean. Nó xử lý nó độc đáo. –

98

Nếu dây của bạn trong smoking cột là những giá trị boolean đã hợp lệ, tuyên bố sau đây sẽ thay đổi kiểu cột mà không làm mất dữ liệu:

change_column :users, :smoking, 'boolean USING CAST(smoking AS boolean)' 

Tương tự, bạn có thể sử dụng bản tuyên Bố này để đúc cột để nguyên:

change_column :table_name, :column_name, 'integer USING CAST(column_name AS integer)' 

Tôi đang sử dụng Postgres. Bạn không chắc chắn liệu giải pháp này có hiệu quả với các cơ sở dữ liệu khác hay không.

+0

phù hợp với tôi - cảm ơn! – ncherro

+2

Chỉ để tránh bất kỳ sự nhầm lẫn nào: có, bạn đang nêu rõ cột mới của mình hai lần. Hãy suy nghĩ về nó như là xác nhận bạn muốn làm điều này và không đưa ra hướng dẫn như thế nào biến foo thành một bool – MCB

6

Vì vậy thích hợp cho boolean trong postgres:

change_column :table_name, :field,'boolean USING (CASE field WHEN \'your any string as true\' THEN \'t\'::boolean ELSE \'f\'::boolean END)' 

và bạn có thể thêm một số chi tiết WHEN - điều kiện THEN trong biểu

của bạn Đối với các máy chủ cơ sở dữ liệu khác, khái niệm sẽ được xây dựng dựa trên cú pháp cho máy chủ cơ sở dữ liệu của bạn, nhưng nguyên tắc là như nhau. Chỉ có thuật toán chuyển đổi thủ công, hoàn toàn không có SQL, không đủ không may.

Way với cú pháp change_column :table, :filed, 'boolean USING CAST(field AS boolean)' chỉ phù hợp nếu các nội dung của một cái gì đó lĩnh vực như: đúng/sai/null

Các vấn đề liên quan