2013-04-26 18 views
50

Vorrei aggiungere un vincolo che impone l'unicità su una colonna solo in una porzione di una tabella.Postgresql: vincolo condizionalmente univoco

ALTER TABLE stop ADD CONSTRAINT myc UNIQUE (col_a) WHERE (col_b is null); 

La parte WHERE è un pio desiderio.

Qualsiasi modo per farlo? O dovrei tornare al tavolo da disegno relazionale?

+0

Ciò è stato già risposto qui: http://stackoverflow.com/questions/469471/how-do-i-alter-a-postgresql-table-and-make-a-column- unique – yvesonline

+2

Comunemente fatto. Vedi "indice univoco parziale" –

+10

@ yvesonline no, è un normale vincolo univoco. Il manifesto desidera un vincolo univoco * parziale *. –

risposta

92

PostgreSQL non definisce un parziale (cioè condizionale) UNIQUE vincolo - tuttavia, è possibile creare un parziale unica indice. PostgreSQL utilizza indici univoci per implementare vincoli univoci, quindi l'effetto è lo stesso, semplicemente non vedrai la risorsa elencata in information_schema.

CREATE UNIQUE INDEX stop_myc ON stop (col_a) WHERE (col_b is null); 

Vedere partial indexes.

+13

Super! Non intuitivo che il "vincolo" non si presenta come un vincolo, ma fornisce comunque l'errore desiderato di ERRORE: valore chiave duplicato viola il vincolo univoco "stop_myc" ' – EoghanM

+2

Vale la pena notare che ciò non consentirà la creazione di riferimenti FK quel campo parzialmente unico. – amenadiel

1

è già stato detto che PG non definisce un vincolo UNIQUE parziale (cioè condizionale). Anche la documentazione dice che il modo migliore per aggiungere un vincolo univoco a una tabella è ADD CONSTRAINTUnique Indexes

The preferred way to add a unique constraint to a table is ALTER TABLE ... ADD CONSTRAINT. The use of indexes to enforce unique constraints could be considered an implementation detail that should not be accessed directly. One should, however, be aware that there's no need to manually create indexes on unique columns; doing so would just duplicate the automatically-created index.

C'è un modo per implementare utilizzando Exclusion Constraints, (grazie @dukelion per questa soluzione)

Nel tuo caso sarà simile

ALTER TABLE stop 
    ADD CONSTRAINT stop_col_a_key_part EXCLUDE (col_a WITH =) WHERE (col_b IS null); 
+0

su questo approccio non si usa "using" per definire il metodo index, in modo che possa essere estremamente lento o postgres crei un indice di default su quello? Questo metodo è la scelta canonica, ma non è mai la scelta migliore! Penso che avrai bisogno di una clausola "using" con indice per fare in modo che quella scelta sia la migliore. –