sql >> Base de Datos >  >> RDS >> PostgreSQL

Función PostgreSQL para la última ID insertada

( tl;dr :vaya a la opción 3:INSERTAR con RETORNO)

Recuerde que en postgresql no existe el concepto de "id" para tablas, solo secuencias (que normalmente, pero no necesariamente, se utilizan como valores predeterminados para claves primarias sustitutas, con el pseudotipo SERIAL).

Si está interesado en obtener la identificación de una fila recién insertada, hay varias formas:

Opción 1:CURRVAL(<sequence name>); .

Por ejemplo:

  INSERT INTO persons (lastname,firstname) VALUES ('Smith', 'John');
  SELECT currval('persons_id_seq');

El nombre de la secuencia debe ser conocido, es realmente arbitrario; en este ejemplo asumimos que la tabla persons tiene un id columna creada con el SERIAL pseudo-tipo. Para evitar depender de esto y sentirse más limpio, puede usar en su lugar pg_get_serial_sequence :

  INSERT INTO persons (lastname,firstname) VALUES ('Smith', 'John');
  SELECT currval(pg_get_serial_sequence('persons','id'));

Advertencia:currval() solo funciona después de un INSERT (que ha ejecutado nextval() ), en la misma sesión .

Opción 2:LASTVAL();

Esto es similar al anterior, solo que no necesita especificar el nombre de la secuencia:busca la secuencia modificada más reciente (siempre dentro de su sesión, la misma advertencia que arriba).

Ambos CURRVAL y LASTVAL son totalmente seguros concurrentes. El comportamiento de la secuencia en PG está diseñado para que las diferentes sesiones no interfieran, por lo que no hay riesgo de condiciones de carrera (si otra sesión inserta otra fila entre mi INSERCIÓN y mi SELECCIÓN, todavía obtengo mi valor correcto).

Sin embargo tienen un problema potencial sutil. Si la base de datos tiene algún DISPARADOR (o REGLA) que, al insertarse en persons tabla, hace algunas inserciones adicionales en otras tablas... luego LASTVAL probablemente nos dará un valor incorrecto. El problema puede ocurrir incluso con CURRVAL , si las inserciones adicionales se realizan en las mismas persons mesa (esto es mucho menos habitual, pero el riesgo aún existe).

Opción 3:INSERT con RETURNING

INSERT INTO persons (lastname,firstname) VALUES ('Smith', 'John') RETURNING id;

Esta es la forma más limpia, eficiente y segura de obtener la identificación. No tiene ninguno de los riesgos del anterior.

¿Inconvenientes? Casi ninguno:es posible que deba modificar la forma en que llama a su declaración INSERT (en el peor de los casos, tal vez su capa API o DB no espera que un INSERT devuelva un valor); no es SQL estándar (a quién le importa); está disponible desde Postgresql 8.2 (diciembre de 2006...)

Conclusión:si puede, elija la opción 3. En otros lugares, prefiera la 1.

Nota:todos estos métodos son inútiles si tiene la intención de obtener la última identificación insertada globalmente (no necesariamente por su sesión). Para esto, debe recurrir a SELECT max(id) FROM table (por supuesto, esto no leerá inserciones no confirmadas de otras transacciones).

Por el contrario, nunca use SELECT max(id) FROM table en lugar de una de las 3 opciones anteriores, para obtener la identificación recién generada por su INSERT declaración, porque (aparte del rendimiento) esto no es seguro concurrente:entre su INSERT y tu SELECT otra sesión podría haber insertado otro registro.