2012-08-09 32 views
31

Scrivo una funzione in PL/pgSQL e sto cercando il modo più semplice per verificare se esiste una riga.
In questo momento sto selezionando uno integer in un boolean, che in realtà non funziona. Non ho ancora abbastanza esperienza con PL/pgSQL per conoscere il modo migliore per farlo.PL/pgSQL verifica se esiste una riga

Ecco parte della mia funzione:

DECLARE person_exists boolean; 
BEGIN 

person_exists := FALSE; 

SELECT "person_id" INTO person_exists 
    FROM "people" p 
WHERE p.person_id = my_person_id 
LIMIT 1; 

IF person_exists THEN 
    -- Do something 
END IF; 

END; $$ LANGUAGE plpgsql; 

Aggiornamento - che sto facendo qualcosa di simile per la società:

DECLARE person_exists integer; 
BEGIN 

person_exists := 0; 

SELECT count("person_id") INTO person_exists 
    FROM "people" p 
WHERE p.person_id = my_person_id 
LIMIT 1; 

IF person_exists < 1 THEN 
    -- Do something 
END IF; 

risposta

90

Più semplice, più breve, più veloce:EXISTS.

IF EXISTS (SELECT 1 FROM people WHERE person_id = my_person_id) THEN 
    -- do something 
END IF; 

Il pianificatore di query può fermarsi alla prima fila trovati - a differenza count(), che esplorerà tutte le righe corrispondenti indipendentemente. Fa la differenza con i grandi tavoli. Difficilmente importa con una condizione su una colonna univoca - solo una riga si qualifica comunque (e c'è un indice per cercarlo rapidamente).

Migliorato con l'input da @a_horse_with_no_name nei commenti seguenti.

+0

Buon punto! (Anche se person_id è probabilmente la chiave primaria, quindi farebbe solo una "scansione" di una singola tabella usando una ricerca di indice). –

+0

@a_horse_with_no_name: A partire da ora (Postgres 9.1) 'count()' * sempre * attiva una scansione sequenziale. Prova 'EXPLAIN ANALYZE SELECT count (id) da tbl' con qualsiasi tabella. Altro su [conteggio lento nel Wiki di Postgres] (http://wiki.postgresql.org/wiki/Slow_Counting). La nuova scansione solo indice di Postgres 9.2 dovrebbe migliorare le cose, perché può (a patto che alcune condizioni) utilizzi una scansione indice per 'count (id)' - devono ancora provarlo e vederlo da solo, però .. –

+3

A 'count (*)' * con una condizione * (specialmente non sulla colonna PK) ** non ** attiva una scansione sequenziale. –

2

Usa count (*)

declare 
    cnt integer; 
begin 
    SELECT count(*) INTO cnt 
    FROM people 
    WHERE person_id = my_person_id; 

IF cnt > 0 THEN 
    -- Do something 
END IF; 

Modifica (per il downvoter chi non ha letto la dichiarazione e altri che potrebbero fare qualcosa di simile)

La soluzione è solo valida perché c'è una clausola where su una colonna (e il nome della colonna suggerisce che è la chiave primaria - quindi la clausola where è altamente efficace)

A causa di tale clausola where non è necessario utilizzare un LIMIT o qualcos'altro per verificare la presenza di una riga identificata dalla sua chiave primaria. È è un modo efficace per testare questo.

+0

Haha Ho aggiunto questa soluzione al mio post proprio come hai postato questo. – nnyby

+2

Non utilizzare COUNT per questo scopo - si tratta di un problema di prestazioni - o devi utilizzare la tabella derivata SELECT COUNT (*) FROM (SELECT * FROM persone LIMIT 1) x –

+1

@PavelStehule: anche quando c'è una condizione 'where' su la ** chiave primaria **? Non riesco a immaginare come potrebbe essere molto più lento della tua affermazione. Il piano di esecuzione è quasi identico per entrambe le soluzioni. –