2011-07-23 24 views

Respuesta

18

esto podría ayudar, aunque puede ser un poco de un truco sucio:

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' 

Entonces llamar con:

SELECT create_constraint_if_not_exists(
     'foo', 
     'bar', 
     'ALTER TABLE foo ADD CONSTRAINT bar CHECK (foobies < 100);') 

Actualizado:

Según Webmut's answer a continuación sugiere:

ALTER TABLE foo DROP CONSTRAINT IF EXISTS bar; 
ALTER TABLE foo ADD CONSTRAINT bar ...; 

Eso es probablemente muy bien en su base de datos de desarrollo, o donde se sabe que se puede excluir a las aplicaciones que dependen de esta base de datos para una ventana de mantenimiento.

Pero si se trata de un entorno de producción animado vitalicio las 24 horas del día, 7 días a la semana, en realidad no es conveniente dejar caer las limitaciones de esta forma. Incluso durante unos pocos milisegundos, hay una breve ventana en la que ya no está aplicando su restricción que puede permitir que los valores erróneos se salgan. Eso puede tener consecuencias no deseadas que conducen a considerables costos comerciales en algún momento del camino.

+0

Creo que ''myconstraint'' debería ser' 'bar'' en tu último ejemplo. –

+0

@denis - bien atrapado. Gracias. – Kev

+0

Modificaría más esta respuesta para que la instrucción de ejecución sea 'ejecutar 'ALTER TABLE' || t_name || 'AGREGAR RESTRICCIÓN' || c_name || '' || constraint_sql; 'y llamar a la función se vería como' SELECT create_constraint_if_not_exists ('foo', 'bar', 'CHECK (foobies <100);'); '. Esto garantiza que no se puedan desordenar los argumentos en su restricción SQL porque están basados ​​en los parámetros originales. –

9

puede ejecutar la consulta sobre pg_constraint tabla para encontrar limitación existe o not.like:

SELECT 1 FROM pg_constraint WHERE conname = 'constraint_name'" 
+3

No se una opción 'IF EXISTS' para' DROP CONSTRAINT' pero, AFAIK, nada para 'ADD CONSTRAINT'. –

+0

¿Los nombres de restricciones son locales en una tabla? ¿Qué sucede si hay dos tablas con una restricción llamada 'constraint_name'? – guettli

+0

Sí, podría obtener falsos positivos si otra tabla tuviera el mismo nombre de restricción. Pero esta sigue siendo una solución decente si tienes el 100% de control sobre tu nombre. –

-1

¿No sabes por qué tantas líneas de código?

- SELECCIONE "Columna1", "Columna2", "Columna3", recuento (estrella) DE dbo. "MiTabla" GRUPO POR "Columna1", "Columna2", "Columna3" TIENE conteo (*)> 1;

alter table dbo. Restricción de caída "MyTable" si existe "MyConstraint_Name";

ALTER TABLE dbo. "MyTable" ADD CONSTRAINT "MyConstraint_Name" UNIQUE ("Column1", "Column3", "Column2");

33

Una posible solución es simplemente usar DROP IF EXISTS antes de crear la nueva restricción.

ALTER TABLE foo DROP CONSTRAINT IF EXISTS bar; 
ALTER TABLE foo ADD CONSTRAINT bar ...; 

parece más fácil que intentar consultar INFORMATION_SCHEMA o catálogos, pero podría ser lento en grandes mesas ya que siempre recrea la restricción.

Editar 2015-07-13: Kev señaló en his answer que mi solución crea una ventana corta cuando la restricción no existe y no se está aplicando. Si bien esto es cierto, puede evitar dicha ventana con bastante facilidad envolviendo ambas declaraciones en una transacción.

11

Puede usar un manejador de excepciones dentro de un bloque de DO anónimo para capturar el error de objeto duplicado.

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.htmlhttp://www.postgresql.org/docs/9.4/static/plpgsql-control-structures.html http://www.postgresql.org/docs/9.4/static/errcodes-appendix.html

+2

Tuve que cambiar 'duplicate_object' por' duplicate_table' (código 42P07). Postgres 9.6 – volvpavl

0

limitaciones Creación puede ser una operación costosa en una tabla que contiene una gran cantidad de datos de las limitaciones por lo que no recomiendo que caen sólo para crear inmediatamente de nuevo inmediatamente después - sólo desea crear ese Lo una vez.

me eligieron para resolver este usando un bloque de código anónimo, muy similar a Mike Stankavich, sin embargo a diferencia de Mike (que coge un error) La primera vez que comprobar para ver si existe la restricción:

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$$;

Cuestiones relacionadas