Hat Postgres eine Möglichkeit zu sagen, ALTER TABLE foo ADD CONSTRAINT bar ...
welche den Befehl einfach ignoriert, wenn die Einschränkung bereits vorhanden ist, damit kein Fehler ausgelöst wird?
quelle
Hat Postgres eine Möglichkeit zu sagen, ALTER TABLE foo ADD CONSTRAINT bar ...
welche den Befehl einfach ignoriert, wenn die Einschränkung bereits vorhanden ist, damit kein Fehler ausgelöst wird?
Dies könnte helfen, obwohl es ein bisschen schmutzig sein kann:
create or replace function create_constraint_if_not_exists (
t_name text, c_name text, constraint_sql text
)
returns void AS
$$
begin
-- Look for our constraint
if not exists (select constraint_name
from information_schema.constraint_column_usage
where table_name = t_name and constraint_name = c_name) then
execute constraint_sql;
end if;
end;
$$ language 'plpgsql'
Dann rufen Sie an mit:
SELECT create_constraint_if_not_exists(
'foo',
'bar',
'ALTER TABLE foo ADD CONSTRAINT bar CHECK (foobies < 100);')
Aktualisiert:
Wie pro Webmut Antwort unten darauf hindeutet:
ALTER TABLE foo DROP CONSTRAINT IF EXISTS bar;
ALTER TABLE foo ADD CONSTRAINT bar ...;
Das ist wahrscheinlich in Ihrer Entwicklungsdatenbank in Ordnung, oder wenn Sie wissen, dass Sie die von dieser Datenbank abhängigen Apps für ein Wartungsfenster schließen können.
Aber wenn dies eine lebhafte, geschäftskritische Produktionsumgebung ist, die rund um die Uhr verfügbar ist, möchten Sie Einschränkungen nicht so oder so fallen lassen. Selbst für einige Millisekunden gibt es ein kurzes Fenster, in dem Sie Ihre Einschränkung nicht mehr erzwingen, wodurch möglicherweise fehlerhafte Werte durchgehen. Dies kann unbeabsichtigte Folgen haben und irgendwann zu erheblichen Geschäftskosten führen.
'myconstraint'
sollte'bar'
in Ihrem letzten Beispiel sein.execute 'ALTER TABLE ' || t_name || ' ADD CONSTRAINT ' || c_name || ' ' || constraint_sql;
und der Aufruf der Funktion dann so aussehen würdeSELECT create_constraint_if_not_exists('foo', 'bar', 'CHECK (foobies < 100);');
. Dies stellt sicher, dass Sie die Argumente in Ihrer Einschränkungs-SQL nicht durcheinander bringen können, da sie auf den ursprünglichen Parametern basieren.execute
Satzes (vorher;
), damit ich das Nachfolgen;
des Arguments beim Aufrufen der Funktion beseitigen kann .information_schema.table_constraints
tut dies.Eine mögliche Lösung besteht darin, einfach DROP IF EXISTS zu verwenden, bevor die neue Einschränkung erstellt wird.
ALTER TABLE foo DROP CONSTRAINT IF EXISTS bar; ALTER TABLE foo ADD CONSTRAINT bar ...;
Scheint einfacher zu sein als der Versuch, information_schema oder Kataloge abzufragen, kann jedoch bei großen Tabellen langsam sein, da die Einschränkung immer neu erstellt wird.
Bearbeiten 2015-07-13: Kev wies in seiner Antwort darauf hin, dass meine Lösung ein kurzes Fenster erstellt, wenn die Einschränkung nicht existiert und nicht durchgesetzt wird. Während dies zutrifft, können Sie ein solches Fenster ganz einfach vermeiden, indem Sie beide Anweisungen in eine Transaktion einschließen.
quelle
Sie können einen Ausnahmebehandler in einem anonymen DO-Block verwenden, um den doppelten Objektfehler abzufangen.
DO $$ BEGIN BEGIN ALTER TABLE foo ADD CONSTRAINT bar ... ; EXCEPTION WHEN duplicate_object THEN RAISE NOTICE 'Table constraint foo.bar already exists'; END; END $$;
http://www.postgresql.org/docs/9.4/static/sql-do.html http://www.postgresql.org/docs/9.4/static/plpgsql-control-structures.html http: // www. postgresql.org/docs/9.4/static/errcodes-appendix.html
quelle
duplicate_object
zuduplicate_table
(Code 42P07). Postgres 9.6duplicate_object
.duplicate_object
fürFOREIGN KEY
.duplicate_table
fürUNIQUE
Einschränkungen. Postgres 9.6.8Sie können eine Abfrage über eine
pg_constraint
Tabelle ausführen, um festzustellen, ob eine Einschränkung vorhanden ist oder nicht.SELECT 1 FROM pg_constraint WHERE conname = 'constraint_name'"
quelle
IF EXISTS
Option für,DROP CONSTRAINT
aber, AFAIK, nichts fürADD CONSTRAINT
.constraint_name
?Das Erstellen von Einschränkungen kann eine teure Operation für eine Tabelle mit vielen Daten sein. Ich empfehle daher, Einschränkungen nicht nur zu löschen, um sie sofort danach erneut zu erstellen. Sie möchten das Objekt nur einmal erstellen.
Ich habe mich entschieden, dies mit einem anonymen Codeblock zu lösen, der Mike Stankavich sehr ähnlich ist. Im Gegensatz zu Mike (der einen Fehler abfängt) überprüfe ich jedoch zuerst, ob die Einschränkung besteht:
DO $$ BEGIN IF NOT EXISTS ( SELECT constraint_schema , constraint_name FROM information_schema.check_constraints WHERE constraint_schema = 'myschema' AND constraint_name = 'myconstraintname' ) THEN ALTER TABLE myschema.mytable ADD CONSTRAINT myconstraintname CHECK (column <= 100); END IF; END$$;
quelle
information_schema.constraint_column_usage
stattdessen verwenden, was mir die Kontrolle über die Namen gab, die ich lesen konnte, sowie über den Tabellennamen.In Anbetracht aller oben genannten Antworten hilft der folgende Ansatz, wenn Sie nur überprüfen möchten, ob in der Tabelle, in die Sie einfügen möchten, eine Einschränkung vorhanden ist, und gegebenenfalls eine Benachrichtigung auslösen möchten
DO $$ BEGIN IF NOT EXISTS (select constraint_name from information_schema.table_constraints where table_schema='schame_name' and upper(table_name) = upper('table_name') and upper(constraint_name) = upper('constraint_name')) THEN ALTER TABLE TABLE_NAME ADD CONSTRAINT CONTRAINT_NAME..... ; ELSE raise NOTICE 'Constraint CONTRAINT_NAME already exists in Table TABLE_NAME'; END IF; END $$;
quelle
Sie wissen nicht, warum so viele Codezeilen?
- SELECT "Column1", "Column2", "Column3", count (star) FROM dbo. "MyTable" GROUP BY "Column1", "Column2", "Column3" HAVING count (*)> 1;
alter table dbo. "MyTable" Drop-Einschränkung, falls vorhanden "MyConstraint_Name";
ALTER TABLE dbo. "MyTable" ADD CONSTRAINT "MyConstraint_Name" UNIQUE ("Column1", "Column3", "Column2");
quelle