6.4. Retorno de datos de filas modificadas #

A veces es útil obtener datos de las filas modificadas mientras se manipulan. Los comandos INSERT, UPDATE, DELETE y MERGE tienen una cláusula opcional RETURNING que admite esto. El uso de RETURNING evita realizar una consulta adicional a la base de datos para recopilar los datos, y es especialmente valioso cuando de otro modo sería difícil identificar las filas modificadas de manera confiable.

Los contenidos permitidos de una cláusula RETURNING son los mismos que los de la lista de salida de un comando SELECT (ver la Section 7.3). Puede contener nombres de columnas de la tabla de destino del comando, o expresiones de valores utilizando esas columnas. Una abreviatura común es RETURNING *, que selecciona todas las columnas de la tabla de destino en orden.

En un INSERT, los datos predeterminados disponibles para RETURNING son la fila tal como fue insertada. Esto no es tan útil en inserciones triviales, ya que solo repetiría los datos proporcionados por el cliente. Pero puede ser muy práctico cuando se confía en valores predeterminados calculados. Por ejemplo, al usar una columna serial para proporcionar identificadores únicos, RETURNING puede devolver el ID asignado a una nueva fila:

CREATE TABLE users (firstname text, lastname text, id serial primary key);

INSERT INTO users (firstname, lastname) VALUES ('Joe', 'Cool') RETURNING id;

La cláusula RETURNING también es muy útil con INSERT ... SELECT.

En un UPDATE, los datos predeterminados disponibles para RETURNING es el nuevo contenido de la fila modificada. Por ejemplo:

UPDATE products SET price = price * 1.10
  WHERE price <= 99.99
  RETURNING name, price AS new_price;

En un DELETE, los datos predeterminados disponibles para RETURNING es el contenido de la fila eliminada. Por ejemplo:

DELETE FROM products
  WHERE obsoletion_date = 'today'
  RETURNING *;

En un MERGE, los datos predeterminados disponibles para RETURNING es el contenido de la fila de origen más el contenido de la fila de destino insertada, actualizada o eliminada. Dado que es bastante común que el origen y el destino tengan muchas de las mismas columnas, especificar RETURNING * puede provocar muchas columnas duplicadas, por lo que a menudo es más útil calificarlo para devolver solo la fila de origen o la de destino. Por ejemplo:

MERGE INTO products p USING new_products n ON p.product_no = n.product_no
  WHEN NOT MATCHED THEN INSERT VALUES (n.product_no, n.name, n.price)
  WHEN MATCHED THEN UPDATE SET name = n.name, price = n.price
  RETURNING p.*;

En cada uno de estos comandos, también es posible devolver explícitamente el contenido antiguo y nuevo de la fila modificada. Por ejemplo:

UPDATE products SET price = price * 1.10
  WHERE price <= 99.99
  RETURNING name, old.price AS old_price, new.price AS new_price,
            new.price - old.price AS price_change;

En este ejemplo, escribir new.price es lo mismo que escribir simplemente price, pero hace que el significado sea más claro.

Esta sintaxis para devolver valores antiguos y nuevos está disponible en los comandos INSERT, UPDATE, DELETE y MERGE, pero normalmente los valores antiguos serán NULL para un INSERT, y los nuevos valores serán NULL para un DELETE. Sin embargo, existen situaciones en las que todavía puede ser útil para esos comandos. Por ejemplo, en un INSERT con una cláusula ON CONFLICT DO UPDATE, los valores antiguos no serán NULL para las filas en conflicto. Del mismo modo, si un DELETE se convierte en un UPDATE mediante una regla de reescritura, los nuevos valores pueden ser no NULL.

Si hay disparadores o triggers (Chapter 37) en la tabla de destino, los datos disponibles para RETURNING son la fila modificada por los disparadores. Por lo tanto, inspeccionar las columnas calculadas por los disparadores es otro caso de uso común para RETURNING.