2010-06-25 11 views
16

Ho una funzione che viene utilizzata come trigger INSERT. Questa funzione elimina le righe che sarebbero in conflitto con [il numero di serie in] della riga che si sta inserendo. Funziona magnificamente, quindi preferirei non discutere i meriti del concetto.Variabile contenente il numero di righe interessate dal precedente DELETE? (in una funzione)

DECLARE 
re1 feeds_item.shareurl%TYPE; 
BEGIN 
SELECT regexp_replace(NEW.shareurl, '/[^/]+(-[0-9]+\.html)$','/[^/]+\\1') INTO re1; 
RAISE NOTICE 'DELETEing rows from feeds_item where shareurl ~ ''%''', re1; 

DELETE FROM feeds_item where shareurl ~ re1; 
RETURN NEW; 
END; 

Vorrei aggiungere all'AVVISO un'indicazione di quante righe sono interessate (ovvero: eliminate). Come posso farlo (usando LANGUAGE 'plpgsql')?

UPDATE: Base su qualche guida eccellente da "pollo in cucina", ho cambiato a questo:

DECLARE 
re1 feeds_item.shareurl%TYPE; 
num_rows int; 
BEGIN 
SELECT regexp_replace(NEW.shareurl, '/[^/]+(-[0-9]+\.html)$','/[^/]+\\1') INTO re1; 

DELETE FROM feeds_item where shareurl ~ re1; 
IF FOUND THEN 
    GET DIAGNOSTICS num_rows = ROW_COUNT; 
    RAISE NOTICE 'DELETEd % row(s) from feeds_item where shareurl ~ ''%''', num_rows, re1; 
END IF; 
RETURN NEW; 
END; 

risposta

9

In Oracle PL/SQL, la variabile di sistema per memorizzare il numero di cancellati/inserite/righe aggiornate è:

SQL%ROWCOUNT 

Dopo un'istruzione DELETE/INSERT/UPDATE, e prima di commettere, è possibile memorizzare SQL% ROWCOUNT in una variabile di tipo NUMBER. Ricordare che COMMIT o ROLLBACK ripristina su ZERO il valore di SQL% ROWCOUNT, quindi è necessario copiare il valore SQL% ROWCOUNT in una variabile PRIMA COMMIT o ROLLBACK.

Esempio:

BEGIN 
    DECLARE 
     affected_rows NUMBER DEFAULT 0; 
    BEGIN 
     DELETE FROM feeds_item 
      WHERE shareurl = re1; 

     affected_rows := SQL%ROWCOUNT; 
     DBMS_OUTPUT. 
     put_line (
      'This DELETE would affect ' 
     || affected_rows 
     || ' records in FEEDS_ITEM table.'); 
     ROLLBACK; 
    END; 
END; 

ho trovato anche questa soluzione interessante (fonte: http://markmail.org/message/grqap2pncqd6w3sp)

On 4/7/07, Karthikeyan Sundaram ha scritto:

Ciao,

I am using 8.1.0 postgres and trying to write a plpgsql block. In that I am inserting a row. I want to check to see if the row has been 

inserito o no.

in Oracle possiamo dire come questo

begin 
    insert into table_a values (1); 
    if sql%rowcount > 0 
    then 
    dbms.output.put_line('rows inserted'); 
    else 
    dbms.output.put_line('rows not inserted'); 
end if; end; 

C'è qualcosa uguale a SQL% rowcount in postgres? Per favore aiuto.

saluti skarthi

Forse:

http://www.postgresql.org/docs/8.2/static/plpgsql-statements.html#PLPGSQL-STATEMENTS-SQL-ONEROW

Clicca sul link qui sopra, vedrete questo contenuto:

37.6.6. Ottenere lo stato dei risultati Esistono diversi modi per determinare l'effetto di un comando. Il primo metodo consiste nell'utilizzare il comando GET DIAGNOSTICA, che ha la forma:

GET variabile DIAGNOSTICA = item [...]; Questo comando permette recupero di indicatori di stato del sistema. Ogni elemento è una parola chiave che identifica un valore di stato da assegnare alla variabile specificata (che dovrebbe essere del tipo di dati corretto per riceverlo).Gli attuali articoli di stato sono ROW_COUNT, il numero di righe elaborate da l'ultimo comando SQL inviato al motore SQL e RESULT_OID, l'OID dell'ultima riga inserita dal più recente comando SQL. Notare che RESULT_OID è utile solo dopo un comando INSERT in una tabella contenente OID.

Un esempio:

DIAGNOSTICA GET integer_var = ROW_COUNT; Il secondo metodo per determinare gli effetti di un comando è controllare la variabile speciale denominata FOUND, che è di tipo booleano. FOUND inizia falso entro ogni chiamata di funzione PL/pgSQL. Viene impostato da ciascuno dei seguenti tipi: di dichiarazioni:

Un'istruzione SELECT INTO imposta FOUND true se viene assegnata una riga, false se non viene restituita alcuna riga.

Un'istruzione PERFORM imposta FOUND true se produce (e scarta) una riga , false se non viene generata alcuna riga.

Le istruzioni UPDATE, INSERT e DELETE impostano FOUND true se è interessata almeno una riga , false se nessuna riga è interessata.

Un'istruzione FETCH imposta FOUND true se restituisce una riga, false se non viene restituita nessuna riga .

Un'istruzione FOR imposta FOUND true se itera una o più volte, altrimenti false. Questo vale per tutte e tre le varianti dell'istruzione FOR (loop FOR intero, loop FOR record-set e record di record dinamico FOR per i cicli ). FOUND è impostato in questo modo quando termina il ciclo FOR; all'interno dell'esecuzione del loop , FOUND non viene modificato dall'istruzione FOR, , sebbene possa essere modificato dall'esecuzione di altre istruzioni all'interno del corpo del loop all'interno di .

FOUND è una variabile locale all'interno di ciascuna funzione PL/pgSQL; eventuali modifiche influiscono solo sulla funzione corrente.

+2

Sì, ROW_COUNT è quello che ti serve. –

+1

fantastico, grazie! –

+2

Non è affatto utile citare il manuale. I collegamenti vanno bene. Ma vengo a StackOverflow per esempi. – Neil

7

Per una soluzione molto robusta, che fa parte di PostgreSQL SQL e non solo plpgsql si potrebbe anche effettuare le seguenti operazioni:

with a as (DELETE FROM feeds_item WHERE shareurl ~ re1 returning 1) 
select count(*) from a; 

Si può effettivamente ottenere un sacco maggiori informazioni:

with a as (delete from sales returning amount) 
select sum(amount) from a; 

per visualizzare i totali, in questo modo è possibile ottenere qualsiasi aggregato e persino raggruppare e filtrarlo.

+0

Penso che dovrebbe essere 'shareurl ~ re1'. A parte questo, ottima risposta! Lo aggiungerò al mio bagaglio di trucchi. –

+0

Se questo è un passaggio controllato quale tipo di variabile è 'a'? –

+0

purtroppo, questa sintassi non funziona in Greenplum (Postgress 8.2) – ekkis

1

vorrei condividere il mio codice (ho avuto questa idea da Roelof Rossouw):

CREATE OR REPLACE FUNCTION my_schema.sp_delete_mytable(_id integer) 
    RETURNS integer AS 
$BODY$ 
    DECLARE 
    AFFECTEDROWS integer; 
    BEGIN 
    WITH a AS (DELETE FROM mytable WHERE id = _id RETURNING 1) 
    SELECT count(*) INTO AFFECTEDROWS FROM a; 
    IF AFFECTEDROWS = 1 THEN 
     RETURN 1; 
    ELSE 
     RETURN 0; 
    END IF; 
    EXCEPTION WHEN OTHERS THEN 
    RETURN 0; 
    END; 
$BODY$ 
    LANGUAGE plpgsql VOLATILE 
    COST 100; 
Problemi correlati