2013-02-07 9 views
10

Sto utilizzando PostgreSQL 9.2 e devo aggiungere un vincolo condizionale su una colonna. In sostanza, voglio assicurarmi che una colonna sia falsa quando altre due colonne hanno un determinato valore.Postgres 9.2 - aggiungi controllo condizionale dei vincoli

gid   | int_unsigned   | not null default 0 
realm  | character varying(255) | not null default ''::character varying 
grant_update | smallint_unsigned  | not null default (0)::smallint 
grant_delete | smallint_unsigned  | not null default (0)::smallint 

Esempio:

alter table node_access add constraint block_anonymous_page_edit 
check (grant_update = 0 WHERE (gid = 1 AND realm = 'nodeaccess_rid')); 

Ciò che dovrebbe fare è assicurarsi che grant_update è uguale a 0 quando GID è 1 e regno = nodeaccess_rid. Tuttavia, penso piuttosto che fare ciò che voglio, in realtà sto cercando di far sì che tutte le colonne imitino questi valori. In sostanza, sta cercando di assicurarsi che grant_update sia sempre 0, gid è sempre 1, e realm è sempre nodeaccess_rid. L'errore che ottengo è:

ERROR: check constraint "block_anonymous_page_edit" is violated by some row 

EDIT

Credo che questo sta andando ad avere per essere una funzione che viene attivata aggiornata.

EDIT

ho aggiunto una riga alla domanda di cui sopra, e di conseguenza ha aggiornato la soluzione approvata con un commento qui sotto.

+0

'' int_unsigned' e smallint_unsigned' sono tipi non-esistenti in Postgres . Per favore ripulisci la tua domanda. –

+0

inesistente o no, è così che scorre il nostro database. La domanda, così com'è, è corretta. – thepriebe

risposta

15

Una volta che avvolgere la mente intorno la logica è piuttosto semplice CHECK constraint:

CREATE TABLE tbl (
    gid   int  NOT NULL DEFAULT 0 
    ,realm  text  NOT NULL DEFAULT '' 
    ,grant_update smallint NOT NULL DEFAULT 0 
    ,CHECK (gid <> 1 
      OR realm <> 'nodeaccess_rid' 
      OR grant_update = 0) 
); 

prova:

INSERT INTO tbl(gid, realm, grant_update) 
VALUES (1, 'nodeaccess_rid', 0);   -- works 

INSERT INTO tbl(gid, realm, grant_update) 
VALUES (1, 'nodeaccess_rid', 1);   -- check violation! 

INSERT INTO tbl(gid, realm, grant_update) 
VALUES (1, 'some_string', 1);   -- works 

INSERT INTO tbl(gid, realm, grant_update) 
VALUES (2, 'nodeaccess_rid', 1);   -- works 
+0

Ho modificato leggermente la tua soluzione per incorporare un aspetto che non ho incluso nella mia domanda. C'è un attributo aggiuntivo che consente agli utenti o agli utenti anonimi di eliminare le pagine, non solo di aggiornarle. Così ora appare come 'CHECK (gid <> 1 O realm <> 'nodeaccess_rid' OR grant_update = 0 OR grant_delete = 0)' – thepriebe

+0

La soluzione attuale assomiglia a questa, 'alter table se esiste node_access add constraint chk_block_anonymous_page_edit check (gid <> 1 o realm <> 'nodeaccess_rid' o grant_update = 0 o grant_delete = 0); ' – thepriebe

+0

Presumo che tu sappia che questo vincolo consente a' grant_update' * o * 'grant_delete' di essere' 0' per detto caso, ma non necessariamente entrambi. –

3

Scrivo come trigger. Questo ti dà la flessibilità di generare un errore (potenzialmente con un codice personalizzato che può essere meglio testato) o semplicemente gestire il problema e impostare grant_update = 0 quando gid = 1 e realm = 'nodeaccess_rid'

0

Ho finito per andare con la funzione trigger. Questo controllerà il ruolo e disabiliterà la funzionalità indesiderata con i campi booleani grant_update e grant_delete. La funzione seguente conserva anche il valore grant_view piuttosto che sovrascriverlo.

CREATE OR REPLACE function block_anonymous_page_edit() 
RETURNS trigger AS $function$ 
BEGIN 
    IF NEW.gid = 1 AND NEW.realm != 'nodeaccess_author' AND (NEW.grant_update = 1 OR NEW.grant_delete = 1) THEN 
    RAISE WARNING 'Anonymous users are not allowed to edit pages.'; 
    NEW.grant_update := 0; 
    NEW.grant_delete := 0; 
    END IF; 
    RETURN NEW; 
END; 
$function$ LANGUAGE plpgsql; 

CREATE TRIGGER tgr_block_anonymous_page_edit BEFORE INSERT OR UPDATE ON node_access FOR EACH ROW EXECUTE PROCEDURE block_anonymous_page_edit();