Ändern Sie den Typ des Varchar-Felds in eine Ganzzahl: "Kann nicht automatisch in eine Ganzzahl umgewandelt werden."

153

Ich habe eine kleine Tabelle und ein bestimmtes Feld enthält den Typ " Zeichen variieren ". Ich versuche es in " Integer " zu ändern, aber es gibt einen Fehler, dass Casting nicht möglich ist.

Gibt es einen Weg, dies zu umgehen, oder sollte ich einfach eine andere Tabelle erstellen und die Datensätze mithilfe einer Abfrage in diese Tabelle einfügen?

Das Feld enthält nur ganzzahlige Werte.

itsols
quelle
Welche spezifische ALTER TABLE haben Sie versucht und wie lautete die spezifische Fehlermeldung?
Mu ist zu kurz
@muistooshort Ich habe versucht, alter von phppgadmin zu verwenden. Wählte die Spalte aus und versuchte, den neuen Feldtyp einzugeben. Der Fehler ist:SQL error: ERROR: column "MID" cannot be cast to type integer
itsols
3
Zunächst wird die Tabelle gesichert. Anschließend können Sie in derselben Tabelle eine weitere Spalte (z. B. Feld2) vom Typ Integer erstellen. Wählen Sie den Wert für Umwandlung in Ganzzahl von Feld1 in Feld2 aus. Benennen Sie dann die Spalte um.
Igor
@Igor aber die neue Spalte fällt am Ende der Tabelle richtig? Kann ich es nicht in der gleichen Position haben?
Itsols
2
@itsols Die Sorge um die Spaltenpositionen ist normalerweise ein Zeichen für ein zweifelhaftes Anwendungsdesign. Sie möchten fast immer explizit benannte Spalten und SELECTListen verwenden, ohne sich auf die Ordnungspositionen der Spalten zu verlassen. Der in den Antworten angegebene Ansatz behält jedoch die Spaltenposition bei.
Craig Ringer

Antworten:

263

Es gibt keine implizite (automatische) Umwandlung von textoder varcharnach integer(dh Sie können a nicht varcharan eine Funktion übergeben, integerdie ein varcharFeld erwartet oder einem Feld zuweist). Daherinteger müssen Sie eine explizite Umwandlung mit ALTER TABLE ... ALTER COLUMN ... TYPE angeben. .. VERWENDUNG :

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

Beachten Sie, dass Ihre Textfelder möglicherweise Leerzeichen enthalten. Verwenden Sie in diesem Fall:

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

Leerzeichen vor dem Konvertieren entfernen.

Dies sollte aus einer Fehlermeldung ersichtlich sein, wenn der Befehl ausgeführt wurde psql, aber es ist möglich, dass PgAdmin-III Ihnen nicht den vollständigen Fehler anzeigt . Folgendes passiert, wenn ich es in psqlPostgreSQL 9.2 teste:

=> 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        

Vielen Dank an @muistooshort für das Hinzufügen des USINGLinks.

Siehe auch diese verwandte Frage ; Es geht um Rails-Migrationen, aber die zugrunde liegende Ursache ist dieselbe und die Antwort gilt.

Wenn der Fehler weiterhin auftritt, hängt er möglicherweise nicht mit Spaltenwerten zusammen, aber Indizes über diese Spalte oder Spaltenstandardwerte schlagen möglicherweise fehl. Indizes müssen vor ALTER COLUMN gelöscht und danach neu erstellt werden. Standardwerte sollten entsprechend geändert werden.

Craig Ringer
quelle
Danke dass du dir die Zeit nimmst. Aber ich kann das scheinbar nicht zum Laufen bringen. Ich habe Ihre ALTER-Zeile ausprobiert und es gibt mir einen Fehler "Syntaxfehler in der Nähe von Using"
itsols
Meine Aussage: ALTER TABLE "tblMenus" ALTER COLUMN "MID" USING (trim ("MID") :: integer);
Itsols
1
@itsols Ganz mein Fehler; Ich habe es korrigiert, als ich Ihren Kommentar sah. Siehe überarbeitet. Es war richtig im Demo-Code, nur nicht das generische Beispiel am Anfang.
Craig Ringer
Tausend Dank! Diese Antwort hat mir viel Ärger und Zeit gespart. Ich frage mich, warum weder Phppgadmin noch Pgadmin dies als Feature haben ...
Itsols
@itsols Die meisten Mitglieder des Kernteams interessieren sich nicht so sehr für PgAdmin, und nur wenige von ihnen verwenden es. Es hat einige nervige Usability-Warzen und Funktionseinschränkungen. Dies ist nur einer von vielen. Da nur wenige Experten PgAdmin verwenden, sind sie nicht so motiviert, die Dinge zu beheben, die sie daran stören würden. Ich benutze es nicht selbst, weil ich es psqlviel schneller und einfacher finde . Ich habe vor einiger Zeit
Craig Ringer
69

das hat bei mir funktioniert.

Ändern Sie die varchar-Spalte in int

change_column :table_name, :column_name, :integer

bekam:

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

chnged zu

change_column :table_name, :column_name, 'integer USING CAST(column_name AS integer)'
Bibangamba
quelle
Haben Sie diese Übung mit Daten versucht und waren Ihre Daten intakt?
Itsols
3
solange das, was in der Spalte steht, eine ganze Zahl ist, ja
bibangamba
Bei mir funktioniert es nicht. Ich benutze Ruby 2.2.3 mit Schienen 4.2.3
Thinh D. Bui
@ ThinhD.Bui - Funktioniert für mich, 2.3.0, Schienen 4.2.6
Philip
1
Seien Sie auch vorsichtig mit Standardeinstellungen
Francisco Quintero
17

Sie können es tun wie:

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

oder versuchen Sie dies:

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

Wenn Sie mehr über dieses Thema erfahren möchten, lesen Sie diesen Artikel: https://kolosek.com/rails-change-database-column

Nesha Zoric
quelle
8

Versuchen Sie dies, es wird sicher funktionieren.

Wenn Sie Rails-Migrationen schreiben, um eine Zeichenfolgenspalte in eine Ganzzahl zu konvertieren, sagen Sie normalerweise:

change_column :table_name, :column_name, :integer

PostgreSQL wird sich jedoch beschweren:

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

Der "Hinweis" sagt Ihnen im Grunde, dass Sie bestätigen müssen, dass dies geschehen soll und wie Daten konvertiert werden sollen. Sagen Sie dies einfach in Ihrer Migration:

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

Das Obige ahmt nach, was Sie von anderen Datenbankadaptern wissen. Wenn Sie nicht numerische Daten haben, können die Ergebnisse unerwartet sein (aber Sie konvertieren schließlich in eine Ganzzahl).

Subhash Chandra
quelle
Ich wollte nur noch einen Punkt hinzufügen, seien Sie vorsichtig mit change_column. es ist irreversibel. Ich schlage vor, bei der Migration Auf und Ab zu verwenden, um dies umkehrbar zu machen.
Mukesh Kumar Gupta
2
PG::InvalidTextRepresentation: ERROR: invalid input syntax for integer: ""Fehler passiert
Shaig Khaligli
6

Ich habe das gleiche Problem. Dann wurde mir klar, dass ich einen Standardzeichenfolgenwert für die Spalte hatte, die ich ändern wollte. Durch Entfernen des Standardwerts wurde der Fehler behoben :)

Valdenir Antoglioli Junior
quelle
Auch vorhandene Indizes in dieser Spalte können ein Problem darstellen. Sie müssen vor ALTER gelöscht und danach neu erstellt werden.
Envek
1

Wenn Sie versehentlich oder nicht ganzzahlig mit Textdaten gemischt haben, sollten Sie zunächst den folgenden Aktualisierungsbefehl ausführen (falls nicht, schlägt das Ändern der Tabelle fehl):

UPDATE the_table SET col_name = replace(col_name, 'some_string', '');
webrama.pl
quelle
3
Mit etwas wie wäre es besser, regexp_replace(col_name, '[^0-9.]','','g')wenn Sie versuchen, unerwünschte Zeichen und Leerzeichen zu entfernen. Sie würden etwas ein bisschen anspruchsvolle benötigen , wenn Sie behalten wollen NaNund Infund 10E42wissenschaftliche Notation, though.
Craig Ringer
1

Wenn Sie an einer Entwicklungsumgebung arbeiten (oder an einer Produktionsumgebung, in der möglicherweise Ihre Daten gesichert werden), müssen Sie zuerst die Daten aus dem DB-Feld löschen oder den Wert auf 0 setzen.

UPDATE table_mame SET field_name= 0;

Führen Sie danach die folgende Abfrage aus und führen Sie die Abfrage nach erfolgreicher Ausführung zur Schemamigration aus. Führen Sie anschließend das Migrationsskript aus.

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

Ich denke, es wird dir helfen.

Sandip Rajput
quelle
0

Ich hatte das gleiche Problem. Ich fing an, die Standardeinstellung der Spalte zurückzusetzen.

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