Ubah jenis bidang varchar menjadi bilangan bulat: "tidak dapat dicetak secara otomatis untuk mengetik bilangan bulat"

154

Saya memiliki meja kecil dan bidang tertentu berisi tipe " karakter yang bervariasi ". Saya mencoba mengubahnya ke " Integer " tetapi memberikan kesalahan bahwa casting tidak mungkin.

Apakah ada cara mengatasi ini atau haruskah saya membuat tabel lain dan membawa catatan ke dalamnya menggunakan kueri.

Bidang ini hanya berisi nilai integer.

itsol
sumber
Apa ALTER TABLE spesifik yang Anda coba dan apa pesan kesalahan spesifik?
mu terlalu pendek
@muistooshort Saya mencoba menggunakan alter dari phppgadmin. Memilih kolom dan mencoba memasukkan tipe bidang baru. Kesalahannya adalah:SQL error: ERROR: column "MID" cannot be cast to type integer
itsol
3
Pertama adalah tabel cadangan. Kemudian Anda bisa membuat kolom lain (misalnya bidang2) bertipe integer dalam tabel yang sama. Pilih nilai cast to integer dari field1 ke dalam field2. Kemudian ganti nama kolomnya.
Igor
@ Igor tetapi kolom baru jatuh di ujung meja kan? Tidak bisakah saya memilikinya di posisi yang sama?
itsol
2
@itsols Peduli tentang posisi kolom biasanya merupakan tanda desain aplikasi yang rapuh. Anda hampir selalu ingin menggunakan kolom dan SELECTdaftar yang diberi nama secara eksplisit , tidak bergantung pada posisi ordinal kolom. Yang mengatakan, pendekatan yang diberikan dalam jawaban akan mempertahankan posisi kolom.
Craig Ringer

Jawaban:

264

Tidak ada pemeran implisit (otomatis) dari textatau varcharke integer(yaitu Anda tidak bisa meneruskan varcharfungsi ke mengharapkan integeratau menetapkan varcharbidang ke integersalah satu), jadi Anda harus menentukan pemeran eksplisit menggunakan ALTER TABLE ... ALTER COLUMN ... TYPE. .. MENGGUNAKAN :

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

Perhatikan bahwa Anda mungkin memiliki ruang kosong di bidang teks Anda; dalam hal ini, gunakan:

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

untuk menghapus ruang putih sebelum mengkonversi.

Ini seharusnya sudah jelas dari pesan kesalahan jika perintah dijalankan psql, tetapi mungkin PgAdmin-III tidak menunjukkan kepada Anda kesalahan penuh. Inilah yang terjadi jika saya mengujinya di psqlPostgreSQL 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        

Terima kasih @muistooshort karena menambahkan USINGtautan.

Lihat juga pertanyaan terkait ini ; ini tentang migrasi Rails, tetapi penyebab dasarnya adalah sama dan jawabannya berlaku.

Jika kesalahan masih terjadi, maka itu mungkin terkait bukan dengan nilai kolom, tetapi indeks di atas kolom ini atau nilai default kolom mungkin gagal typecast. Indeks harus dijatuhkan sebelum ALTER COLUMN dan dibuat kembali sesudahnya. Nilai default harus diubah dengan tepat.

Craig Ringer
sumber
Terima kasih telah meluangkan waktu. Tapi sepertinya saya tidak bisa mendapatkan ini bekerja. Saya mencoba garis ALTER Anda dan itu memberi saya kesalahan "Sintaks kesalahan dekat Menggunakan"
itsols
Pernyataan saya: ALTER TABLE "tblMenus" ALTER COLUMN "MID" MENGGUNAKAN (trim ("MID") :: integer);
itsol
1
@itsols Sepenuhnya salahku; Saya memperbaikinya sama seperti saya melihat komentar Anda. Lihat direvisi. Itu benar dalam kode demo, hanya bukan contoh umum di awal.
Craig Ringer
Terima kasih banyak! Jawaban ini menyelamatkan saya dari banyak masalah dan waktu. Saya ingin tahu mengapa niether phppgadmin atau pgadmin memiliki ini sebagai fitur ...
itsols
@itsols Sebagian besar tim inti tidak terlalu tertarik pada PgAdmin, dan beberapa dari mereka menggunakannya. Ini memiliki beberapa kutil kegunaan yang mengganggu dan keterbatasan fungsi. Ini hanya satu dari banyak dari mereka. Karena beberapa ahli menggunakan PgAdmin, mereka tidak termotivasi untuk memperbaiki hal-hal yang akan mengganggu mereka. Saya tidak menggunakannya sendiri, karena saya menemukan psqljauh lebih cepat dan lebih mudah. Saya menulis sedikit kata-kata kasar tentang kegunaan PgAdmin sehubungan dengan backup dan restore beberapa waktu lalu: blog.ringerc.id.au/2012/05/…
Craig Ringer
70

ini bekerja untuk saya.

ubah kolom varchar ke int

change_column :table_name, :column_name, :integer

dapatkan:

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

chnged ke

change_column :table_name, :column_name, 'integer USING CAST(column_name AS integer)'
bibangamba
sumber
Apakah Anda mencoba latihan ini dengan data dan apakah data Anda utuh?
itsols
3
selama apa yang ada di kolom adalah bilangan bulat, ya
bibangamba
Itu tidak bekerja dengan saya. Saya menggunakan ruby ​​2.2.3 dengan rel 4.2.3
Thinh D. Bui
@ ThinhD.Bui - Bekerja untuk saya, 2.3.0, rel 4.2.6
Philip
1
Hati-hati dengan default juga
Francisco Quintero
17

Anda dapat melakukannya seperti:

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

atau coba ini:

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

Jika Anda tertarik untuk menemukan lebih banyak tentang topik ini, baca artikel ini: https://kolosek.com/rails-change-database-column

Nesha Zoric
sumber
8

Coba ini, pasti akan berhasil.

Saat menulis migrasi Rails untuk mengonversi kolom string ke integer, Anda biasanya akan mengatakan:

change_column :table_name, :column_name, :integer

Namun, PostgreSQL akan mengeluh:

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

"Petunjuk" pada dasarnya memberi tahu Anda bahwa Anda perlu mengonfirmasi bahwa Anda ingin ini terjadi, dan bagaimana data akan dikonversi. Katakan saja ini dalam migrasi Anda:

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

Di atas akan meniru apa yang Anda ketahui dari adaptor database lain. Jika Anda memiliki data non-numerik, hasilnya mungkin tidak terduga (tetapi Anda mengkonversi ke integer).

Subhash Chandra
sumber
Saya hanya ingin menambahkan satu poin lagi, hati-hati dengan change_column. itu tidak dapat dipulihkan. Saya sarankan menggunakan naik turun dalam migrasi untuk membuat ini reversibel.
Mukesh Kumar Gupta
2
PG::InvalidTextRepresentation: ERROR: invalid input syntax for integer: ""kesalahan terjadi
Shaig Khaligli
6

Saya mendapat masalah yang sama. Daripada saya sadari saya memiliki nilai string default untuk kolom yang saya coba ubah. Menghapus nilai default membuat kesalahan hilang :)

Valdenir Antoglioli Junior
sumber
Juga indeks yang ada di kolom ini mungkin menjadi masalah. Mereka harus dijatuhkan sebelum ALTER dan diciptakan kembali setelah.
Envek
1

Jika Anda tidak sengaja atau tidak memadukan bilangan bulat dengan data teks, Anda harus terlebih dahulu menjalankan perintah pembaruan di bawah ini (jika tidak di atas tabel ubah akan gagal):

UPDATE the_table SET col_name = replace(col_name, 'some_string', '');
webrama.pl
sumber
3
Anda akan lebih baik dengan sesuatu seperti regexp_replace(col_name, '[^0-9.]','','g')jika Anda mencoba untuk menghapus karakter yang tidak diinginkan dan ruang putih. Anda akan memerlukan sesuatu yang sedikit lebih canggih jika Anda ingin mempertahankan NaNdan Infdan 10E42notasi ilmiah.
Craig Ringer
1

Jika Anda bekerja di lingkungan pengembangan (atau untuk lingkungan produksi mungkin merupakan cadangan data Anda), pertama-tama hapus data dari bidang DB atau tetapkan nilainya sebagai 0.

UPDATE table_mame SET field_name= 0;

Setelah itu jalankan query di bawah ini dan setelah berhasil menjalankan query, ke schemamigration dan setelah itu jalankan skrip migrasi.

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

Saya pikir itu akan membantu Anda.

Sandip Rajput
sumber
0

Saya memiliki masalah yang sama. Saya mulai mengatur ulang default kolom.

change_column :users, :column_name, :boolean, default: nil
change_column :users, :column_name, :integer, using: 'column_name::integer', default: 0, null: false
Maxime Boué
sumber