2011-11-30 12 views
32

Ho controllato la documentazione fornita da Oracle e trovato un modo per modificare un vincolo senza perdere la tabella. Il problema è che si modifica erroneamente in quanto non riconosce la parola chiave.Cercando di modificare un vincolo in PostgreSQL

Utilizzo di EMS SQL Manager per PostgreSQL.

Alter table public.public_insurer_credit MODIFY CONSTRAINT public_insurer_credit_fk1 
    deferrable, initially deferred; 

ho potuto risolvere esso facendo cadere il vincolo utilizzando:

ALTER TABLE "public"."public_insurer_credit" 
    DROP CONSTRAINT "public_insurer_credit_fk1" RESTRICT; 

ALTER TABLE "public"."public_insurer_credit" 
    ADD CONSTRAINT "public_insurer_credit_fk1" FOREIGN KEY ("branch_id", "order_id", "public_insurer_id") 
    REFERENCES "public"."order_public_insurer"("branch_id", "order_id", "public_insurer_id") 
    ON UPDATE CASCADE 
    ON DELETE NO ACTION 
    DEFERRABLE 
    INITIALLY DEFERRED; 
+9

Perché stai controllando la documentazione Oracle (e taggando questa domanda con 'plsql') quando stai usando PostgreSQL? Qual è l'errore esatto (quale parola chiave non è riconosciuta)? – Bruno

+0

ERRORE: errore di sintassi in prossimità o "MODIFICA" LINE 1: Modificare tavolo public.public_insurer_credit MODIFICARE VINCOLO p ... ^ (0,359 sec) – MISMajorDeveloperAnyways

+7

Controllo documentazione Oracle per Postgres, e quindi accusando Postgres. Epico. –

risposta

23

Secondo il manuale corretto (che viene fornita dallo PostgreSQL, non da Oracle), non c'è modify vincolo disponibili nell'istruzione ALTER TABLE:

Ecco il link al manuale di corretta:

http://www.postgresql.org/docs/current/static/sql-altertable.html

+0

Grazie per il link alla documentazione corretta. Sono stato fornito con la documentazione Oracle PL/SQL dal nostro DBA. Figure. – MISMajorDeveloperAnyways

+2

Oracle e Oracle PL/SQL sono cose completamente diverse. L'unica ragione possibile è che si utilizza * Advanced Server * di EnterpriseDB che supporta il PL/SQL di Oracle (e altre funzionalità di compatibilità Oracle). Ma poi avrebbero dovuto darti il ​​manuale EnterpriseDB, non il manuale Oracle –

+1

Qualcuno può spiegare perché questa risposta ha avuto un downvote? –

52

Non esiste il comando ALTER per i vincoli in Postgres. Il modo più semplice per farlo è eliminare il vincolo e aggiungerlo nuovamente con i parametri desiderati. Ovviamente qualsiasi modifica del vincolo verrà eseguita rispetto ai dati della tabella corrente.

BEGIN; 
ALTER TABLE t1 DROP CONSTRAINT ... 
ALTER TABLE t1 ADD CONSTRAINT ... 
COMMIT; 
+14

+1 per farlo in una transazione. –

+5

Attenzione: se ho capito bene, le istruzioni DDL prendono un blocco AccessExclusive sulla tabella, quindi se questi comandi impiegano molto tempo, il tuo sito si fermerà fino al completamento dei comandi. La [pagina di documentazione] (http://www.postgresql.org/docs/current/static/sql-altertable.html) ha più dettagli, incluso come specificare un indice esplicitamente piuttosto che averne uno generato automaticamente. –

25

A partire dalla versione 9.4, PostgreSQL supporta ALTER TABLE ... ALTER CONSTRAINT per chiavi esterne.

Questa funzionalità sarà "Allow constraint attributes to be altered, so the default setting of NOT DEFERRABLE can be altered to DEFERRABLE and back." Guardando la tua domanda Penso che sia (tipo di) quello che stavi cercando.

Informazioni più dettagliate e un esempio può essere trovato qui:
http://www.depesz.com/2013/06/30/waiting-for-9-4-alter-table-alter-constraint-for-fks/

+2

http://www.postgresql.org/docs/9.4/static/sql-altertable.html –

+1

Si noti che i documenti 9.4 dicono "Attualmente solo i vincoli delle chiavi esterne possono essere modificati".! –

+0

@MichaelHerrmann Ho già detto questo nella mia risposta. – mkurz

2

ALTER VINCOLO richiederebbe conoscenza del nome chiave esterna, che non è sempre conveniente.

Questa è la funzione, in cui è necessario conoscere solo i nomi di tabelle e colonne. Uso:

select replace_foreign_key('user_rates_posts', 'post_id', 'ON DELETE CASCADE'); 

Funzione:

CREATE OR REPLACE FUNCTION 
    replace_foreign_key(f_table VARCHAR, f_column VARCHAR, new_options VARCHAR) 
RETURNS VARCHAR 
AS $$ 
DECLARE constraint_name varchar; 
DECLARE reftable varchar; 
DECLARE refcolumn varchar; 
BEGIN 

SELECT tc.constraint_name, ccu.table_name AS foreign_table_name, ccu.column_name AS foreign_column_name 
FROM 
    information_schema.table_constraints AS tc 
    JOIN information_schema.key_column_usage AS kcu 
     ON tc.constraint_name = kcu.constraint_name 
    JOIN information_schema.constraint_column_usage AS ccu 
     ON ccu.constraint_name = tc.constraint_name 
WHERE constraint_type = 'FOREIGN KEY' 
    AND tc.table_name= f_table AND kcu.column_name= f_column 
INTO constraint_name, reftable, refcolumn; 

EXECUTE 'alter table ' || f_table || ' drop constraint ' || constraint_name || 
', ADD CONSTRAINT ' || constraint_name || ' FOREIGN KEY (' || f_column || ') ' || 
' REFERENCES ' || reftable || '(' || refcolumn || ') ' || new_options || ';'; 

RETURN 'Constraint replaced: ' || constraint_name || ' (' || f_table || '.' || f_column || 
' -> ' || reftable || '.' || refcolumn || '); New options: ' || new_options; 

END; 
$$ LANGUAGE plpgsql; 

essere consapevoli: questa funzione non copierà attributi della chiave esterna iniziale. Richiede solo nome tabella/nome colonna esterna, elimina la chiave corrente e sostituisce con uno nuovo.

+0

Soluzione molto interessante – tom10271

Problemi correlati