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?
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?
Antworten:
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.
execute 'ALTER TABLE ' || t_name || ' ADD CONSTRAINT ' || c_name || ' ' || constraint_sql;
und der Aufruf der Funktion dann so aussehen würde SELECT 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.
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
duplicate_object
zu duplicate_table
(Code 42P07). Postgres 9.6
duplicate_object
.
duplicate_object
für FOREIGN KEY
. duplicate_table
für UNIQUE
Einschränkungen. Postgres 9.6.8
Sie 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'"
IF EXISTS
Option für, DROP CONSTRAINT
aber, AFAIK, nichts für ADD 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$$;
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
$$;
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");
'myconstraint'
sollte'bar'
in Ihrem letzten Beispiel sein.