sql >> Databasteknik >  >> RDS >> PostgreSQL

PostgreSQL-funktion för senast infogade ID

( tl;dr :gå till alternativ 3:INFOGA med RETURNERING )

Kom ihåg att det i postgresql inte finns något "id"-koncept för tabeller, bara sekvenser (som vanligtvis men inte nödvändigtvis används som standardvärden för primära surrogatnycklar, med pseudotypen SERIAL).

Om du är intresserad av att få ID för en nyinfogad rad finns det flera sätt:

Alternativ 1:CURRVAL(<sequence name>); .

Till exempel:

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

Namnet på sekvensen måste vara känt, det är verkligen godtyckligt; i detta exempel antar vi att tabellen persons har ett id kolumnen skapad med SERIAL pseudo-typ. För att undvika att lita på detta och för att känna dig renare kan du istället använda pg_get_serial_sequence :

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

Varning:currval() fungerar bara efter en INSERT (som har kört nextval() ), i samma session .

Alternativ 2:LASTVAL();

Detta liknar det föregående, bara att du inte behöver ange sekvensnamnet:det letar efter den senast ändrade sekvensen (alltid i din session, samma varning som ovan).

Båda CURRVAL och LASTVAL är helt säkra samtidigt. Sekvensens beteende i PG är utformat så att olika sessioner inte kommer att störa, så det finns ingen risk för tävlingsförhållanden (om en annan session infogar en annan rad mellan min INSERT och min SELECT, får jag fortfarande mitt korrekta värde).

Men de har ett subtilt potentiellt problem. Om databasen har någon TRIGGER (eller REGEL) som, vid infogning i persons tabell, gör några extra insättningar i andra tabeller... sedan LASTVAL kommer förmodligen att ge oss fel värde. Problemet kan till och med hända med CURRVAL , om de extra infogningarna görs i samma persons tabell (detta är mycket mindre vanligt, men risken finns fortfarande).

Alternativ 3:INSERT med RETURNING

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

Detta är det mest rena, effektiva och säkraste sättet att få ID. Det har inte någon av riskerna med det tidigare.

Nackdelar? Nästan ingen:du kan behöva ändra sättet du anropar din INSERT-sats på (i värsta fall förväntar sig kanske inte ditt API- eller DB-lager att en INSERT returnerar ett värde); det är inte standard SQL (vem bryr sig); den är tillgänglig sedan Postgresql 8.2 (dec 2006...)

Slutsats:Om du kan, välj alternativ 3. På andra ställen, föredra 1.

Obs:alla dessa metoder är värdelösa om du tänker få det senast infogade ID globalt (inte nödvändigtvis av din session). För detta måste du ta till SELECT max(id) FROM table (naturligtvis kommer detta inte att läsa oengagerade bilagor från andra transaktioner).

Omvänt bör du aldrig använd SELECT max(id) FROM table istället ett av de tre alternativen ovan, för att få ID:t som just genererats av din INSERT uttalande, eftersom (bortsett från prestanda) detta inte är samtidigt säkert:mellan din INSERT och din SELECT en annan session kan ha infogat en annan post.



  1. Det gick inte att ansluta till PostgreSQL-servern:kunde inte ansluta till servern:Tillstånd nekad

  2. Infoga data i tabeller länkade med främmande nyckel

  3. Tvinga InnoDB att kontrollera främmande nycklar på ett eller flera tabeller igen?

  4. JDBCTemplate set kapslade POJO med BeanPropertyRowMapper