Funkcja PostgreSQL dla Ostatnio wstawionego ID

W PostgreSQL, Jak mogę wstawić ostatni id do tabeli?

W MS SQL jest SCOPE_IDENTITY ().

Proszę nie radzić mi używać czegoś takiego:

select max(id) from table
Author: jkdev, 2010-05-31

10 answers

( tl;dr : goto option 3: INSERT with RETURNING)

Przypomnijmy, że w postgresql nie ma pojęcia "id" dla tabel, tylko sekwencje (które są zazwyczaj, ale niekoniecznie muszą być używane jako domyślne wartości dla zastępczych kluczy podstawowych, z pseudo-typem } szeregowy).

Jeśli jesteś zainteresowany uzyskaniem id nowo wstawionego wiersza, istnieje kilka sposobów:


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

Na przykład:

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

The nazwa sekwencji musi być znana, jest naprawdę Dowolna; w tym przykładzie zakładamy, że Tabela persons ma kolumnę id utworzoną z pseudo-typu SERIAL. Aby uniknąć polegania na tym i czuć się bardziej czystym, możesz użyć zamiast tego pg_get_serial_sequence:

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

Zastrzeżenie: currval() działa tylko po INSERT (który wykonał nextval() ), w tej samej sesji .


Opcja 2: LASTVAL();

Jest to podobne do poprzedniego, tylko, że nie trzeba podaj nazwę sekwencji: wyszukuje najnowszą zmodyfikowaną sekwencję (zawsze wewnątrz sesji, to samo zastrzeżenie jak powyżej).


Zarówno CURRVAL jak i LASTVAL są całkowicie bezpieczne. Zachowanie sekwencji w PG jest tak zaprojektowane, aby różne sesje nie przeszkadzały, więc nie ma ryzyka warunków wyścigu (jeśli inna sesja wstawi inny wiersz między moją wstawką a moim SELECT, nadal otrzymuję poprawną wartość).

Jednak [26]} mają subtelny potencjał problem. Jeśli baza danych posiada jakąś TRIGGER (lub regułę), która po wstawieniu do tabeli persons powoduje dodatkowe Wstawienia w innych tabelach... wtedy LASTVAL prawdopodobnie poda nam złą wartość. Problem może wystąpić nawet z CURRVAL, Jeśli dodatkowe wstawki są wykonywane w tej samej tabeli persons (jest to znacznie mniej typowe, ale ryzyko nadal istnieje).


Opcja 3: INSERT Z RETURNING

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

Jest to najbardziej czysty, skuteczny i bezpieczny sposób na uzyskanie identyfikatora. To nie ma ŻADNEGO RYZYKA z poprzedniego.

Wady? Prawie żaden: być może będziesz musiał zmodyfikować sposób wywoływania instrukcji INSERT (w najgorszym przypadku, być może Twoja warstwa API lub DB nie oczekuje, że INSERT zwróci wartość); nie jest to standardowy SQL (kogo to obchodzi); jest dostępny od Postgresql 8.2 (grudzień 2006...)


Wniosek: jeśli możesz, wybierz opcję 3. Gdzie indziej, wolę 1.

Uwaga: wszystkie te metody są bezużyteczne, jeśli zamierzasz uzyskać ostatnią globalnie wstawiony id (niekoniecznie w sesji). W tym celu musisz użyć select max(id) from table (oczywiście nie będzie to odczytywać niezatwierdzonych wstawek z innych transakcji).

 464
Author: leonbloy,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-10-14 04:28:04

Patrz klauzula zwracająca INSERT . Zasadniczo INSERT podwaja się jako zapytanie i zwraca wartość, która została wstawiona.

 69
Author: kwatford,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-05-31 15:01:33

Możesz użyć klauzuli zwracającej w instrukcji INSERT, tak jak poniżej

wgzhao=# create table foo(id int,name text);
CREATE TABLE
wgzhao=# insert into foo values(1,'wgzhao') returning id;
 id 
----
  1
(1 row)

INSERT 0 1
wgzhao=# insert into foo values(3,'wgzhao') returning id;
 id 
----
  3
(1 row)

INSERT 0 1

wgzhao=# create table bar(id serial,name text);
CREATE TABLE
wgzhao=# insert into bar(name) values('wgzhao') returning id;
 id 
----
  1
(1 row)

INSERT 0 1
wgzhao=# insert into bar(name) values('wgzhao') returning id;
 id 
----
  2
(1 row)

INSERT 0 
 25
Author: wgzhao,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-08-24 10:25:36

Odpowiedź Leonbloy jest całkiem kompletna. Dodałbym tylko specjalny przypadek, w którym trzeba uzyskać ostatnią wstawioną wartość z funkcji PL / pgSQL, gdzie opcja 3 nie pasuje dokładnie.

Na przykład, jeśli mamy następujące tabele:

CREATE TABLE person(
   id serial,
   lastname character varying (50),
   firstname character varying (50),
   CONSTRAINT person_pk PRIMARY KEY (id)
);

CREATE TABLE client (
    id integer,
   CONSTRAINT client_pk PRIMARY KEY (id),
   CONSTRAINT fk_client_person FOREIGN KEY (id)
       REFERENCES person (id) MATCH SIMPLE
);

Jeśli musimy wstawić rekord klienta, musimy odwołać się do rekordu osoby. Ale powiedzmy, że chcemy opracować funkcję PL / pgSQL, która wstawia nowy rekord do klienta, ale także zajmuje się wstawianiem nowego rekordu osoby. W tym celu musimy użyć lekkiego wariantu wariantu 3 leonbloy ' a:

INSERT INTO person(lastname, firstname) 
VALUES (lastn, firstn) 
RETURNING id INTO [new_variable];

Zauważ, że istnieją dwie klauzule INTO. Dlatego funkcja PL / pgSQL będzie zdefiniowana następująco:

CREATE OR REPLACE FUNCTION new_client(lastn character varying, firstn character varying)
  RETURNS integer AS
$BODY$
DECLARE
   v_id integer;
BEGIN
   -- Inserts the new person record and retrieves the last inserted id
   INSERT INTO person(lastname, firstname)
   VALUES (lastn, firstn)
   RETURNING id INTO v_id;

   -- Inserts the new client and references the inserted person
   INSERT INTO client(id) VALUES (v_id);

   -- Return the new id so we can use it in a select clause or return the new id into the user application
    RETURN v_id;
END;
$BODY$
  LANGUAGE plpgsql VOLATILE;

Teraz możemy wstawić nowe dane używając:

SELECT new_client('Smith', 'John');

Lub

SELECT * FROM new_client('Smith', 'John');

I otrzymujemy nowo utworzony identyfikator.

new_client
integer
----------
         1
 16
Author: Krauss,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-23 11:47:18

Zobacz poniższy przykład

CREATE TABLE users (
    -- make the "id" column a primary key; this also creates
    -- a UNIQUE constraint and a b+-tree index on the column
    id    SERIAL PRIMARY KEY,
    name  TEXT,
    age   INT4
);

INSERT INTO users (name, age) VALUES ('Mozart', 20);

Następnie dla uzyskania ostatnio wstawionego id użyj tego dla tabeli "user" seq nazwa kolumny " id "

SELECT currval(pg_get_serial_sequence('users', 'id'));
 8
Author: RINSON KE,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-04-04 15:47:48
SELECT CURRVAL(pg_get_serial_sequence('my_tbl_name','id_col_name'))

Musisz oczywiście podać nazwę tabeli i nazwę kolumny.

To będzie dla bieżącej sesji / połączenia http://www.postgresql.org/docs/8.3/static/functions-sequence.html

 7
Author: jishi,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-04-04 15:51:34

Dla tych, którzy muszą uzyskać rekord wszystkich danych, możesz dodać

returning *

Na koniec zapytania, aby uzyskać obiekt all wraz z id.

 2
Author: emreoktem,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-01-05 07:45:00

Spróbuj tego:

select nextval('my_seq_name');  // Returns next value

Jeśli zwróci 1 (lub jakąkolwiek wartość startową dla Twojej sekwencji), zresetuj sekwencję z powrotem do pierwotnej wartości, przekazując fałszywą flagę:

select setval('my_seq_name', 1, false);

Inaczej,

select setval('my_seq_name', nextValue - 1, true);

Spowoduje przywrócenie wartości sekwencji do stanu pierwotnego, a" setval " powróci z wartością sekwencji, której szukasz.

 1
Author: Oozman,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-02-27 18:09:30

Postgres ma wbudowany mechanizm tego samego, który w tym samym zapytaniu zwraca id lub cokolwiek chcesz, aby zapytanie zwróciło. oto przykład. Załóżmy, że masz utworzoną tabelę, która ma kolumny 2 column1 i column2 i chcesz, aby kolumna 1 była zwracana po każdej wstawce.

# create table users_table(id serial not null primary key, name character varying);
CREATE TABLE
#insert into users_table(name) VALUES ('Jon Snow') RETURNING id;
 id 
----
  1
(1 row)

# insert into users_table(name) VALUES ('Arya Stark') RETURNING id;
 id 
----
  2
(1 row)
 0
Author: Sandip Debnath,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-08-30 11:49:44

Jeśli potrzebujesz tylko pobrać ostatnio wstawiony identyfikator bez wstawiania czegokolwiek, możesz użyć poniższego przykładu

SELECT id FROM users ORDER BY id DESC LIMIT 1;
Nadzieja może pomóc.
 -4
Author: MattC,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-10-21 13:14:21