2010-06-25 34 views
16

Tengo una función que se utiliza como un disparador INSERTAR. Esta función elimina las filas que entrarían en conflicto con [el número de serie en] la fila que se está insertando. Funciona muy bien, así que preferiría no debatir los méritos del concepto.¿Variable que contiene el número de filas afectadas por el DELETE previo? (en una función)

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; 

Me gustaría agregar al AVISO una indicación de cuántas filas están afectadas (también conocido como: eliminado). ¿Cómo puedo hacer eso (usando LANGUAGE 'plpgsql')?

ACTUALIZACIÓN: Base en un excelente orientación de "Pollo en la cocina", he cambiado a esto:

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; 

Respuesta

9

En Oracle PL/SQL, la variable de sistema para almacenar el número de filas eliminadas/insertadas/actualizados es:

SQL%ROWCOUNT 

Después de una instrucción DELETE/INSERT/UPDATE y antes de comprometerse, puede almacenar% ROWCOUNT de SQL en una variable de tipo NUMBER. Recuerde que COMMIT o ROLLBACK restablecen a cero el valor de SQL% ROWCOUNT, por lo que debe copiar el valor de SQL% ROWCOUNT en una variable ANTES de COMMIT o ROLLBACK.

Ejemplo:

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; 

He encontrado también interesante esta solución (fuente: http://markmail.org/message/grqap2pncqd6w3sp)

En 07/04/07, Karthikeyan Sundaram escribió:

Hola,

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 

insertado o no.

en Oracle podemos decir como esto

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; 

¿Hay algo igual a sql% del recuento de filas en Postgres? Por favor ayuda.

Saludos skarthi

Tal vez:

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

Haga clic en el enlace de arriba, verá este contenido:

37.6.6. Obtención del estado del resultado Hay varias formas de determinar el efecto de un comando. El primer método es utilizar el comando GET DIAGNOSTICS, que tiene la forma:

obtener la variable DIAGNOSTICS = item [, ...]; Este comando permite recuperación de los indicadores de estado del sistema. Cada elemento es una palabra clave que identifica un valor de estado que se asignará a la variable especificada (que debe ser del tipo de datos correcto para recibirla).Los actualmente elementos de estado disponibles son ROW_COUNT, el número de filas procesadas por el último comando SQL enviado al motor SQL y RESULT_OID, OID de la última fila insertada por el comando SQL más reciente. Tenga en cuenta que RESULT_OID solo es útil después de un comando INSERT en una tabla que contiene OID.

Un ejemplo:

GET DIAGNOSTICS integer_var = ROW_COUNT; El segundo método para determinar los efectos de un comando es comprobar la variable especial llamada FOUND, que es de tipo booleano. FOUND comienza falso dentro de cada llamada de función PL/pgSQL. Se establece por cada uno de los siguientes tipos de instrucciones:

Una instrucción SELECT INTO establece FOUND verdadero si se asigna una fila, falso si no se devuelve ninguna fila.

Una instrucción PERFORM establece FOUND verdadero si produce (y descarta) una fila , falso si no se produce ninguna fila.

Las sentencias UPDATE, INSERT y DELETE establecen FOUND verdadero si se ve afectado al menos una fila , falso si no se ve ninguna fila.

Un enunciado FETCH establece FOUND verdadero si devuelve una fila, falso si no se devuelve la fila .

Una declaración FOR establece que se encuentre verdadero si itera una o más veces, de lo contrario es falso. Esto se aplica a las tres variantes de la instrucción FOR (bucles enteros FOR, bucles FOR configurados en registros y bucles dinámicos FOR- ). FOUND se establece de esta manera cuando el ciclo FOR sale; dentro de la ejecución del bucle, FOUND no se modifica mediante la instrucción FOR, aunque puede modificarse mediante la ejecución de otras instrucciones dentro del cuerpo del bucle .

FOUND es una variable local dentro de cada función PL/pgSQL; cualquier cambio afecta solo a la función actual.

+2

Sí, ROW_COUNT es lo que necesita. –

+1

impresionante, gracias! –

+2

Citar el manual no es del todo útil. Los enlaces están bien. Pero vengo a stackoverflow para ver ejemplos. – Neil

7

Para una solución muy robusta, que es parte de PostgreSQL SQL y no sólo plpgsql también se puede hacer lo siguiente:

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

En realidad se puede obtener mucha más información, tales como:

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

para ver totales, de esta manera puede obtener cualquier agregado e incluso agruparlo y filtrarlo.

+0

Creo que debería ser 'shareurl ~ re1'. ¡Aparte de eso, gran respuesta! Agregaré esto a mi bolsa de trucos. –

+0

Si este es un procedimiento sombreado, ¿qué tipo de variable es 'a'? –

+0

lamentablemente, esta sintaxis no funciona en Greenplum (Postgress 8.2) – ekkis

1

lo haría para compartir mi código (que tenía esta idea de 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; 
Cuestiones relacionadas