Zmień typ pola varchar na integer: „nie można rzutować automatycznie na typ integer”

154

Mam małą tabelkę i pewne pole zawiera typ „ zmienny znak ”. Próbuję zmienić to na „ Integer ”, ale wyświetla błąd, że przesyłanie nie jest możliwe.

Czy istnieje sposób na obejście tego, czy powinienem po prostu utworzyć inną tabelę i wprowadzić do niej rekordy za pomocą zapytania.

Pole zawiera tylko wartości całkowite.

itsols
źródło
Jakiego rodzaju ALTER TABLE wypróbowałeś i jaki był konkretny komunikat o błędzie?
mu jest za krótkie
@muistooshort Próbowałem użyć alter z phppgadmin. Wybrano kolumnę i próbowano wprowadzić nowy typ pola. Błąd jest następujący:SQL error: ERROR: column "MID" cannot be cast to type integer
itsols
3
Pierwsza to kopia zapasowa tabeli. Następnie możesz utworzyć kolejną kolumnę (powiedzmy field2) typu całkowitego w tej samej tabeli. Wybierz rzutowanie na wartość całkowitą z pola 1 na pole 2. Następnie zmień nazwę kolumny.
Igor
@Igor ale nowa kolumna wypada na koniec tabeli, prawda? Czy nie mogę mieć tego w tej samej pozycji?
itsols
2
@itsols Dbanie o pozycje kolumn jest zwykle oznaką niepewnego projektu aplikacji. Prawie zawsze chcesz używać jawnie nazwanych kolumn i SELECTlist, a nie polegać na pozycjach porządkowych kolumn. To powiedziawszy, podejście podane w odpowiedziach zachowa pozycję kolumny.
Craig Ringer

Odpowiedzi:

264

Nie ma niejawnego (automatycznego) rzutowania z textlub varchardo integer(tj. Nie można przekazać a varchardo funkcji oczekującej integerlub przypisanej varcharpola do integerjedynki), więc należy określić jawne rzutowanie za pomocą ALTER TABLE ... ALTER COLUMN ... TYPE. .. UŻYWANIE :

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

Zauważ, że możesz mieć spacje w polach tekstowych; w takim przypadku użyj:

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

aby usunąć odstępy przed konwersją.

Powinno to wynikać z komunikatu o błędzie, jeśli polecenie zostało uruchomione psql, ale możliwe, że PgAdmin-III nie pokazuje pełnego błędu. Oto, co się stanie, jeśli przetestuję go w 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        

Dzięki @muistooshort za dodanie USINGlinku.

Zobacz także to powiązane pytanie ; chodzi o migracje Railsów, ale przyczyna jest taka sama i odpowiedź ma zastosowanie.

Jeśli błąd nadal występuje, może to być związane nie z wartościami kolumn, ale indeksy w tej kolumnie lub wartości domyślne kolumny mogą zakończyć się niepowodzeniem. Indeksy należy usunąć przed ALTER COLUMN i ponownie utworzyć po. Wartości domyślne należy odpowiednio zmienić.

Craig Ringer
źródło
Dziękuję Ci za poświęcenie czasu. Ale nie wydaje mi się, żeby to działało. Wypróbowałem linię ALTER i wyświetla mi się komunikat o błędzie „Błąd składni w pobliżu używania”
itsols
Moje oświadczenie: ALTER TABLE "tblMenus" ALTER COLUMN "MID" USING (trim ("MID") :: integer);
itsols
1
@itsols Całkowicie mój błąd; Poprawiłem to tak, jak zobaczyłem twój komentarz. Zobacz poprawione. To było słuszne w kodzie demonstracyjnym, ale nie był ogólnym przykładem na początku.
Craig Ringer
Stukrotne dzięki! Ta odpowiedź zaoszczędziła mi wielu kłopotów i czasu. Zastanawiam się, dlaczego niether phppgadmin ani pgadmin mają to jako funkcję ...
itsols
@itsols Większość podstawowego zespołu nie jest zainteresowana PgAdmin i niewielu z nich go używa. Ma pewne irytujące brodawki użyteczności i ograniczenia funkcjonalności. To tylko jeden z wielu z nich. Ponieważ niewielu ekspertów używa PgAdmin, nie są oni tak zmotywowani do naprawiania rzeczy, które mogłyby ich denerwować. Sam go nie używam, ponieważ znajduję psqldużo szybciej i łatwiej. Niedawno napisałem rant o użyteczności PgAdmina w zakresie tworzenia kopii zapasowych i przywracania: blog.ringerc.id.au/2012/05/...
Craig Ringer
70

to działało dla mnie.

zmień kolumnę varchar na int

change_column :table_name, :column_name, :integer

dostał:

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

chnged to

change_column :table_name, :column_name, 'integer USING CAST(column_name AS integer)'
bibangamba
źródło
czy wykonałeś to ćwiczenie z danymi i czy Twoje dane były nienaruszone?
itsols
3
o ile to, co jest w kolumnie, jest liczbą całkowitą, tak
bibangamba
Ze mną to nie działa. Używam Ruby 2.2.3 z szynami 4.2.3
Thinh D. Bui
@ ThinhD.Bui - Works for me, 2.3.0, rails 4.2.6
Philip
1
Uważaj również na wartości domyślne
Francisco Quintero
17

Możesz to zrobić tak:

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

lub spróbuj tego:

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

Jeśli chcesz dowiedzieć się więcej na ten temat, przeczytaj ten artykuł: https://kolosek.com/rails-change-database-column

Nesha Zoric
źródło
8

Spróbuj tego, na pewno zadziała.

Pisząc migracje Railsów, aby przekonwertować kolumnę łańcuchową na liczbę całkowitą, zwykle powiesz:

change_column :table_name, :column_name, :integer

Jednak PostgreSQL będzie narzekać:

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

„Wskazówka” w zasadzie mówi ci, że musisz potwierdzić, że chcesz, aby tak się stało i jak dane mają być konwertowane. Po prostu powiedz to podczas migracji:

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

Powyższe będzie naśladować to, co znasz z innych adapterów baz danych. Jeśli masz dane nieliczbowe, wyniki mogą być nieoczekiwane (ale mimo wszystko konwertujesz na liczbę całkowitą).

Subhash Chandra
źródło
Chciałem tylko dodać jeszcze jeden punkt, uważaj na change_column. jest nieodwracalne. Sugeruję użycie w migracji w górę iw dół, aby było to odwracalne.
Mukesh Kumar Gupta
2
PG::InvalidTextRepresentation: ERROR: invalid input syntax for integer: ""zdarza się błąd
Shaig Khaligli
6

Mam ten sam problem. Potem zdałem sobie sprawę, że mam domyślną wartość ciągu dla kolumny, którą próbowałem zmienić. Usunięcie wartości domyślnej sprawiło, że błąd zniknął :)

Valdenir Antoglioli Junior
źródło
Problemem mogą być również istniejące indeksy w tej kolumnie. Należy je upuścić przed ALTER i odtworzyć po.
Envek
1

Jeśli przypadkowo zmieszałeś liczby całkowite z danymi tekstowymi lub nie, powinieneś najpierw wykonać poniższe polecenie update (jeśli nie powyżej, zmiana tabeli nie powiedzie się):

UPDATE the_table SET col_name = replace(col_name, 'some_string', '');
webrama.pl
źródło
3
Lepiej byłoby zrobić coś takiego, regexp_replace(col_name, '[^0-9.]','','g')jeśli próbujesz usunąć niechciane znaki i spacje. Że trzeba coś nieco bardziej wyrafinowane, jeśli chcesz zachować NaNi Infi 10E42notacji naukowej, choć.
Craig Ringer,
1

Jeśli pracujesz na środowisku programistycznym (lub na środowisku produkcyjnym, może to być kopia zapasowa danych), najpierw wyczyść dane z pola DB lub ustaw wartość na 0.

UPDATE table_mame SET field_name= 0;

Następnie, aby uruchomić poniższe zapytanie, a po pomyślnym uruchomieniu zapytania, do schematu migracji, a następnie uruchom skrypt migracji.

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

Myślę, że to ci pomoże.

Sandip Rajput
źródło
1

Miałem ten sam problem. Zacząłem resetować domyślne ustawienia kolumny.

change_column :users, :column_name, :boolean, default: nil
change_column :users, :column_name, :integer, using: 'column_name::integer', default: 0, null: false
Maxime Boué
źródło