Ich habe eine Tabelle und muss eine neue Spalte ohne Standardwert hinzufügen:
Zwang:
ALTER TABLE integrations.billables
DROP CONSTRAINT IF EXISTS cc_at_least_one_mapping_needed_billables,
ADD CONSTRAINT cc_at_least_one_mapping_needed_billables
CHECK ((("qb_id" IS NOT NULL) :: INTEGER +
("xero_id" IS NOT NULL) :: INTEGER +
("freshbooks_id" IS NOT NULL) :: INTEGER +
("unleashed_id" IS NOT NULL) :: INTEGER +
("csv_data" IS NOT NULL) :: INTEGER +
("myob_id" IS NOT NULL) :: INTEGER) > 0);
Säule:
ALTER TABLE integrations.billables
DROP COLUMN IF EXISTS myob_id,
ADD COLUMN myob_id varchar(255);
Frage:
Wie kann ich die Einschränkung für die nächsten Werte hinzufügen und nicht für diejenigen, die bereits vorhanden sind? (Andernfalls würde die Fehlerprüfungsbeschränkung "" durch eine Zeile verletzt).
Dies hängt mit meiner vorherigen Frage zusammen: FEHLER: Die Prüfbedingung wird durch eine Zeile verletzt
postgresql
database-design
postgresql-9.2
null
check-constraints
Gemeinschaft
quelle
quelle
myob_id
ohne die in der Tabelle vorhandene Spalte erwähnt wird ?Antworten:
Markieren Sie alle vorhandenen Zeilen als alt:
Und richten Sie die Einschränkung so ein, dass alte Zeilen ignoriert werden:
(Ja, diese
IS NULL
Prüfung funktioniert. Siehe hier .)Vorteile dieses Mechanismus:
Nachteile:
boolean
Spalte oder einen anderen Reifensprung für die zweite neue Spalte hinzufügen .is_old
Flagge umdrehen könntetrue
. (Dies kann jedoch behoben werden. Siehe unten.) Dies ist kein Grund zur Sorge, wenn Endbenutzer nicht direkt auf die Datenbank zugreifen können und Sie darauf vertrauen können, dass die Entwickler keine verrückten Dinge mit den Daten tun.Wenn Sie sich über jemanden Änderung der Flagge besorgt, könnten Sie einen Trigger einrichten, um alle Einsätze oder Updates zu verhindern Einstellung
is_old
zutrue
:Sie müssen immer noch darauf vertrauen, dass niemand, der das Datenbankschema ändern kann, Ihren Trigger oder etwas anderes fallen lässt, aber wenn er das tut, kann er auch die Einschränkung fallen lassen.
Hier ist eine SQLFiddle-Demo . Beachten Sie, dass die Zeile "sollte überspringen" nicht in der Ausgabe enthalten ist (wie gewünscht).
quelle
UPDATE
dauerte 349422 ms (5,8 Minuten). Das Anwenden eines ähnlichenCHECK
Vorgangs dauerte 20996 ms (21 Sekunden). Das sind insgesamt ca. 10 Minuten. Dies alles war auf einem ziemlich leistungsschwachen Computer (4 GB RAM, Dual-Core-CPU). Sie haben etwas weniger als das Dreifache der Anzahl der Zeilen. Wenn die Laufzeit linear wächst, was ich erwartet hatte, sprechen Sie von einer halben Stunde Ausfallzeit, die in vielen Zusammenhängen äußerst vernünftig ist. Aber testen Sie die Laufzeiten selbst.Wenn Sie eine
serial
Spalte oder eine Ganzzahl haben, die automatisch mit a gefüllt wirdnextval
(sodass Sie niemals neue Zeilen mit einem expliziten Wert für diese Spalte einfügen sollen), können Sie zusätzlich prüfen, ob der Wert dieser Spalte größer als ein bestimmter Wert ist ::wo die
value
bestimmt werden sollencurrval
die Säule / entsprechende Sequenz zu der Zeit des Änderns / Neuerstellung der Einschränkung.Auf diese Weise gelten die
IS NOT NULL
Prüfungen nur für die Zeilen, derenYourSerialColumn
Wert größer als istvalue
.Hinweis
Dies kann als Variation des Vorschlags von David Spillet angesehen werden . Der Hauptunterschied liegt in der Tatsache, dass diese Lösung keine strukturellen Änderungen (Partitionierung) erfordert. Beide Optionen hängen jedoch vom Vorhandensein einer geeigneten Spalte in Ihrer Tabelle ab. Wenn es keine solche Spalte ist , und Sie können es hinzufügen , speziell dieses Problem zu lösen, mit der Partitionierung Idee gehen könnte die bessere Option dieser beiden sein.
quelle
Fügen Sie einfach die Einschränkung als hinzu
NOT VALID
Aus dem Handbuch:
quelle
Dies war in Postgres bis Version 9.1 nicht möglich. Ab 9.2 können Sie eine Prüfbedingung definieren als
NOT VALID
(entsprichtWITH NOCHECK
in MS SQL Server). Weitere Informationen finden Sie unter http://www.postgresql.org/docs/9.2/static/sql-altertable.html .Ich bin im Allgemeinen nicht zufrieden mit solchen Dingen, bei denen es überhaupt möglich ist, sie zu vermeiden. Ein Kompromiss, wenn Sie einen geeigneten Partitionierungsschlüssel haben (z. B. ein Eingabefeld), besteht darin, dass Sie die Tabelle möglicherweise partitionieren und die
NOT NULL
Einschränkung nur auf die Partition anwenden können, die neuere Zeilen enthält. Stellen Sie in beiden Fällen sicher, dass die Entwurfsauswahl gut dokumentiert ist, damit zukünftige Datenbankadministratoren / Entwickler / andere wissen, dass in einer bestimmten Teilmenge der Datensätze in der Tabelle möglicherweise NULL-Werte erwartet werden.quelle
Ihre
CHECK
Einschränkung kann viel einfacher sein:Oder auch nur:
Warum funktioniert das?
Ich habe bereits die
NOT VALID
Klausel hinzugefügt, die @a_horse erwähnt hat . Auf diese Weise gilt die Einschränkung nur für neu hinzugefügte Zeilen. Sie müssen auch mögliche Speicherauszugs- / Wiederherstellungszyklen berücksichtigen. Einzelheiten:Und Sie können alles in einem einzigen Befehl erledigen , der am schnellsten ist und verhindert, dass mögliche gleichzeitige Transaktionen etwas falsch machen:
SQL Fiddle.
Nebenbei 1: Wenn Sie bereits die
CHECK
Einschränkung für denselben Spaltensatz hätten, nur ohne die neuemyob_id
, wäre dies kein Problem, da jede vorhandene Zeile auch die neueCHECK
Einschränkung mit übergeben würdemyob_id
.Nebenbei 2: In einigen RDBMS ist es sinnvoll
varchar(255)
, die Leistung zu optimieren. Dies ist für Postgres und 255 irrelevant, da der Längenmodifikator nur dann sinnvoll ist, wenn Sie die Länge tatsächlich auf maximal 255 beschränken müssen:quelle