Thay đổi loại trường varchar thành số nguyên: Không thể tự động chuyển sang loại số nguyên


154

Tôi có một bảng nhỏ và một trường nhất định chứa loại " ký tự thay đổi ". Tôi đang cố gắng thay đổi nó thành " Integer " nhưng nó gây ra lỗi là không thể truyền.

Có cách nào khác không hay tôi chỉ nên tạo một bảng khác và đưa các bản ghi vào đó bằng truy vấn.

Trường chỉ chứa các giá trị nguyên.


Bạn đã thử ALTER TABLE cụ thể nào và thông báo lỗi cụ thể là gì?
mu quá ngắn

@muistooshort Tôi đã thử sử dụng thay đổi từ phppgadmin. Chọn cột và cố gắng nhập loại trường mới. Lỗi là:SQL error: ERROR: column "MID" cannot be cast to type integer
itols

3
Đầu tiên là để sao lưu bảng. Sau đó, bạn có thể tạo một cột khác (giả sử trường2) của kiểu số nguyên trong cùng một bảng. Chọn giá trị cast tới số nguyên của trường1 vào trường2. Sau đó đổi tên cột.
Igor

@Igor nhưng cột mới rơi ở cuối bảng phải không? Tôi không thể có nó ở cùng một vị trí?
itols

2
@itsols Quan tâm đến vị trí cột thường là dấu hiệu của thiết kế ứng dụng iffy. Bạn hầu như luôn muốn được sử dụng các cột và SELECTdanh sách được đặt tên rõ ràng , không dựa vào các vị trí thứ tự cột. Điều đó nói rằng, cách tiếp cận được đưa ra trong các câu trả lời sẽ bảo vệ vị trí cột.
Craig Ringer

Câu trả lời:


264

Không có đúc (tự động) ẩn từ texthoặc varcharđến integer(nghĩa là bạn không thể truyền một hàm varcharcho một hàm mong đợi integerhoặc gán một varchartrường cho một trường integer), vì vậy bạn phải chỉ định một biểu mẫu rõ ràng bằng cách sử dụng ALTER TABLE ... ALTER COLUMN ... TYPE. .. SỬ DỤNG :

ALTER TABLE the_table ALTER COLUMN col_name TYPE integer USING (col_name::integer);

Lưu ý rằng bạn có thể có khoảng trắng trong các trường văn bản của bạn; trong trường hợp đó, sử dụng:

ALTER TABLE the_table ALTER COLUMN col_name TYPE integer USING (trim(col_name)::integer);

để dải trắng trước khi chuyển đổi.

Điều này rõ ràng từ một thông báo lỗi nếu lệnh được chạy psql, nhưng có thể PGAdmin-III không hiển thị cho bạn toàn bộ lỗi. Đây là những gì xảy ra nếu tôi kiểm tra nó psqltrên PostgreQuery 9.2:

=> CREATE TABLE test( x varchar );
CREATE TABLE
=> insert into test(x) values ('14'), (' 42  ');
INSERT 0 2
=> ALTER TABLE test ALTER COLUMN x TYPE integer;
ERROR:  column "x" cannot be cast automatically to type integer
HINT:  Specify a USING expression to perform the conversion. 
=> ALTER TABLE test ALTER COLUMN x TYPE integer USING (trim(x)::integer);
ALTER TABLE        

Cảm ơn @muistooshort đã thêm USINGliên kết.

Xem thêm câu hỏi liên quan này ; đó là về việc di chuyển Rails, nhưng nguyên nhân cơ bản là như nhau và câu trả lời được áp dụng.

Nếu lỗi vẫn xảy ra, thì nó có thể không liên quan đến các giá trị cột, nhưng các chỉ mục trên cột này hoặc các giá trị mặc định của cột có thể không thành công kiểu chữ. Các chỉ mục cần được loại bỏ trước ALTER COLUMN và được tạo lại sau. Giá trị mặc định nên được thay đổi một cách thích hợp.


Cảm ơn bạn đã dành thời gian. Nhưng tôi dường như không thể làm việc này. Tôi đã thử dòng ALTER của bạn và nó báo lỗi "Lỗi cú pháp gần bằng cách sử dụng"
itols

Tuyên bố của tôi: ALTER TABLE "tblMenus" ALTER COLUMN "MID" SỬ DỤNG (trim ("MID") :: số nguyên);
itols

1
@itsols Hoàn toàn là lỗi của tôi; Tôi đã sửa nó giống như tôi thấy bình luận của bạn. Xem sửa đổi. Nó đã đúng trong mã demo, không phải là ví dụ chung khi bắt đầu.
Craig Ringer

Cảm ơn rất nhiều! Câu trả lời này đã tiết kiệm cho tôi rất nhiều rắc rối và thời gian. Tôi tự hỏi tại sao phppgadmin hay pgadmin mới hơn lại có tính năng này ...
itols

@itsols Hầu hết các nhóm nòng cốt không quan tâm đến PGAdmin và rất ít trong số họ sử dụng nó. Nó có một số mụn cóc khó sử dụng và hạn chế chức năng. Đây chỉ là một trong số nhiều người trong số họ. Bởi vì ít chuyên gia sử dụng PGAdmin, họ không có động lực để sửa chữa những điều khiến họ khó chịu về nó. Tôi không sử dụng nó cho bản thân mình, vì tôi thấy psqlnhanh hơn và dễ dàng hơn nhiều. Tôi đã viết một chút của một rant về pgAdmin khả năng sử dụng liên quan đến sao lưu và khôi phục lại một lúc trước: blog.ringerc.id.au/2012/05/...
Craig Ringer

70

Điều này làm việc cho tôi.

thay đổi cột varchar thành int

change_column :table_name, :column_name, :integer

có:

PG::DatatypeMismatch: ERROR:  column "column_name" cannot be cast automatically to type integer
HINT:  Specify a USING expression to perform the conversion.

kéo đến

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

bạn đã thử bài tập này với dữ liệu và dữ liệu của bạn có còn nguyên vẹn không?
itols

3
miễn là những gì trong cột là một số nguyên, vâng
bibangamba

Nó không hoạt động với tôi. Tôi đang sử dụng ruby ​​2.2.3 với đường ray 4.2.3
Thịnh D. Bùi

@ ThịnhD.Bui - Hoạt động cho tôi, 2.3.0, đường ray 4.2.6
Philip

1
Hãy cẩn thận với các mặc định là tốt
Francisco Quintero

17

Bạn có thể làm điều đó như:

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

hoặc thử điều này:

change_column :table_name, :column_name, :integer, using: 'column_name::integer'

Nếu bạn quan tâm để tìm hiểu thêm về chủ đề này, hãy đọc bài viết này: https://kolosek.com/rails-change-database-column


8

Hãy thử điều này, nó sẽ hoạt động chắc chắn.

Khi viết di chuyển Rails để chuyển đổi một cột chuỗi thành một số nguyên bạn thường nói:

change_column :table_name, :column_name, :integer

Tuy nhiên, PostgreSQL sẽ khiếu nại:

PG::DatatypeMismatch: ERROR:  column "column_name" cannot be cast automatically to type integer
HINT:  Specify a USING expression to perform the conversion.

"Gợi ý" về cơ bản cho bạn biết rằng bạn cần xác nhận bạn muốn điều này xảy ra và cách dữ liệu sẽ được chuyển đổi. Chỉ cần nói điều này trong di chuyển của bạn:

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

Ở trên sẽ bắt chước những gì bạn biết từ các bộ điều hợp cơ sở dữ liệu khác. Nếu bạn có dữ liệu không phải là số, kết quả có thể bất ngờ (nhưng rốt cuộc bạn đang chuyển đổi thành số nguyên).


Tôi chỉ muốn thêm một điểm nữa, hãy cẩn thận với change_column. nó là không thể đảo ngược. Tôi đề nghị sử dụng lên và xuống trong di chuyển để làm cho điều này có thể đảo ngược.
Mukesh Kumar Gupta

2
PG::InvalidTextRepresentation: ERROR: invalid input syntax for integer: ""xảy ra lỗi
Shaig Khaligli

6

Tôi đã có cùng một vấn đề. Hơn tôi nhận ra tôi có một giá trị chuỗi mặc định cho cột tôi đang cố gắng thay đổi. Xóa giá trị mặc định làm cho lỗi biến mất :)


Ngoài ra các chỉ mục hiện có trên cột này có thể là một vấn đề. Chúng cần được loại bỏ trước ALTER và được tạo lại sau.
Envek

1

Nếu bạn vô tình hoặc không trộn lẫn số nguyên với dữ liệu văn bản, trước tiên bạn nên thực hiện bên dưới lệnh cập nhật (nếu không thay đổi bảng sẽ không thành công):

UPDATE the_table SET col_name = replace(col_name, 'some_string', '');

3
Bạn sẽ tốt hơn với một cái gì đó giống như regexp_replace(col_name, '[^0-9.]','','g')nếu bạn đang cố gắng loại bỏ các ký tự và khoảng trắng không mong muốn. Bạn sẽ cần một cái gì đó phức tạp hơn một chút nếu bạn muốn giữ lại NaNInf10E42ký hiệu khoa học, mặc dù.
Craig Ringer

1

Nếu bạn đang làm việc trên môi trường phát triển (hoặc cho sản xuất env. Nó có thể sao lưu dữ liệu của bạn) thì trước tiên hãy xóa dữ liệu khỏi trường DB hoặc đặt giá trị là 0.

UPDATE table_mame SET field_name= 0;

Sau đó để chạy truy vấn bên dưới và sau khi chạy truy vấn thành công, đến sơ đồ và sau đó chạy tập lệnh di chuyển.

ALTER TABLE table_mame ALTER COLUMN field_name TYPE numeric(10,0) USING field_name::numeric;

Tôi nghĩ rằng nó sẽ giúp bạn.


0

Tôi gặp vấn đề tương tự. Tôi bắt đầu thiết lập lại mặc định của cột.

change_column :users, :column_name, :boolean, default: nil
change_column :users, :column_name, :integer, using: 'column_name::integer', default: 0, null: false
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.