Sonntag, April 5, 2020

Postgres: Standardwert für die Spalte (string) kann nicht gewirkt werden, automatisch zu Typ enum

Ich habe eine status Spalte in einer Tabelle, ich will ein enum. Ursprünglich hatte ich vor, erstellt das Feld als integer, und dachte, ich würde verwenden, den eingebauten Schienen, die enum-Funktionalität. Stellt sich heraus, dass erfordert die mindestens Rails 4.1, aber ich bin mit 4.0 und der Prozess der Aktualisierung wird einige Zeit in Anspruch nehmen.

Aber, darüber nachzudenken, wie das alles funktioniert, ich erkannte, dass ich kann haben entweder ein ActiveRecord enum oder eine postgres-enum, nicht für beide. Ich dachte, dass auf lange Sicht eine explizite postgres enum wäre am besten. Also schrieb ich eine migration zu konvertieren, die status Spalte von integer in einen enum.

execute "CREATE TYPE status_options AS ENUM ('pending', 'declined', 'approved');"
change_column :site_applications, :status, "status_options USING status::status_options"

Aber, ich bekomme diese Fehlermeldung:

PG::CannotCoerce: ERROR:  cannot cast type integer to status_options
ALTER TABLE "site_applications" ALTER COLUMN "status" TYPE status_options USING status::status_options

Alles, was ich bisher gesehen habe, in meinem searchings sagt mir, dass sollte gearbeitet haben,, aber es funktioniert nicht. Ich dachte, vielleicht ist das problem, dass ich einfach nicht gehen aus integer enum. So soll es sein. Meine Lösung war, um zuerst konvertieren Sie die Spalte in eine Zeichenfolge und dann versuchen, es zu konvertieren enum.

change_column :site_applications, :status, :string
execute "CREATE TYPE status_options AS ENUM ('pending', 'declined', 'approved');"
change_column :site_applications, :status, "status_options USING status::status_options"

… Und das gibt mir die folgende Fehlermeldung:

PG::DatatypeMismatch: ERROR:  default for column "status" cannot be cast automatically to type status_options
ALTER TABLE "site_applications" ALTER COLUMN "status" TYPE status_options USING status::status_options

Führte mich zu glauben, dass dies etwas zu tun hatte mit der default-Wert, also versuchte ich die Angabe des Standard in der change_column Erklärung:

change_column :site_applications, :status, :string, default: "pending"

Dass die änderungen erfolgreich die Spalte in eine Zeichenfolge der Standardwert ist „offen“, aber change_column schlägt mit der gleichen „default für die Spalte“ Fehler.

Merke ich, dass ich konnte einfach legen Sie die Spalte alle zusammen und erstellen Sie dann es genau so, wie ich will, aber an diesem Punkt ist es eine Frage der nachkommenschaft. Warum zum Teufel kann ich nicht konvertieren, eine Spalte von integer oder string zu enum? Wer?

UPDATE MIT AKZEPTIERTEN ANTWORTEN

Basierend auf Gary ‚ s Antwort da unten, dies ist die migration, arbeitete.

def up
  execute "ALTER TABLE site_applications ALTER status DROP DEFAULT;"
  execute "CREATE TYPE status_options AS ENUM ('pending', 'declined', 'approved');"
  change_column :site_applications, :status, "status_options USING status::status_options", default: "pending"
end

def down
  change_column :site_applications, :status, :string, default: "pending"
  execute "DROP TYPE status_options;"
end
  • Können Sie das zeigen die Ergebnisse einer \dt site_applications in PSQL. Da die Nachricht klingt wie es ist ein Standard-Wert gesetzt gegen die Spalte. Möglicherweise müssen Sie entfernen die Standard -, während Sie die änderung vornehmen und dann wieder hinzufügen einer Voreinstellung des entsprechenden Typs hinterher.
  • Ich denke, Sie sind absolut Recht, aber ich kann nicht für das Leben von mir herauszufinden, welche Art von default zu setzen, so dass es sein kann, wechselte zu einem enum. Aber, ich habe die \dt schema.site_applications – und das ist es, was zurückgegeben: schema | site_applications | table | eliduke
  • sorry, sollte Es gewesen sein \d statt \dt
  • Oh, ok. Hier ist das: status | integer | not null default 0. Aber ich bin nicht überrascht, dass, wirklich, weil, wenn ich versuchte, Sie zu konvertieren integer enum, ich habe Fehler cannot cast type integer to status_options. So, ich dachte, dass da ein enum ist eine Art Variante von einem string, der zunächst würde ich es in einen string konvertieren und dann konvertieren Sie Sie in enum. Und DAS ist, wenn ich bekam die default for column Fehler. An einer Stelle habe ich sogar versucht, die Umwandlung der integer in einen string und setzen den Standard für die string-Spalte auf null und dann die Umwandlung zu enum. Das scheiterte auch mit dem gleichen Fehler.
  • In diesem Fall werden Sie wollen, ein alter table schema.site_applications alter status drop default zu entfernen, die den Standard vollständig. konvertieren Sie den Typ, dann alter table schema.site_applications alter status set default 'pending'::status_options' nicht ganz sicher, ob der Standard-enum-syntax.
  • Das war der Gewinner! Vielen Dank, @Gary. Wenn Sie möchten, schreiben Sie eine Antwort werde ich Holen, die als die Antwort.

InformationsquelleAutor Eli Duke | 2015-07-22

1 Kommentar

  1. 16

    Müssen Sie entfernen Sie den Standardwert aus der Spalte vor der änderung als Standard ist eingestellt auf einen Wert, der gültig ist für die alte Spalte Typ aber nicht kompatibel mit der neuen Art.

    alter table schema.site_applications alter status drop default

    Dann können Sie ändern Sie die Spalte Typ. Schließlich, wenn die neue Spalte vom Typ angewendet wird, können Sie hinzufügen eine neue Standard gegen den Tisch.

    alter table schema.site_applications alter status set default 'pending'::status_options

Kostenlose Online-Tests