it-swarm.dev

Jak korzystać z currval () w PostgreSQL, aby uzyskać ostatni wstawiony identyfikator?

Mam stolik:

CREATE TABLE names (id serial, name varchar(20))

Chcę „ostatni wstawiony identyfikator” z tej tabeli, bez używania RETURNING id Na wstawce. Wygląda na to, że istnieje funkcja CURRVAL() , ale nie rozumiem, jak jej używać.

Próbowałem z:

SELECT CURRVAL() AS id FROM names_id_seq
SELECT CURRVAL('names_id_seq')
SELECT CURRVAL('names_id_seq'::regclass)

ale żaden z nich nie działa. Jak mogę użyć currval(), aby uzyskać ostatni wstawiony identyfikator?

70
Jonas

Jeśli utworzysz kolumnę jako serial PostgreSQL automatycznie utworzy sekwencję dla tego.

Nazwa sekwencji jest generowana automatycznie i zawsze ma nazwę tablename_columnname_seq, w twoim przypadku sekwencją będą nazwy names_id_seq.

Po wstawieniu do tabeli możesz wywołać currval() z tą nazwą sekwencji:

postgres=> CREATE TABLE names in schema_name (id serial, name varchar(20));
CREATE TABLE
postgres=> insert into names (name) values ('Arthur Dent');
INSERT 0 1
postgres=> select currval('names_id_seq');
 currval
---------
       1
(1 row)
postgres=>

Zamiast na stałe wpisywać nazwę sekwencji, możesz także użyć pg_get_serial_sequence() zamiast:

select currval(pg_get_serial_sequence('names', 'id'));

W ten sposób nie musisz polegać na strategii nazewnictwa używanej przez Postgres.

Lub jeśli nie chcesz w ogóle używać nazwy sekwencji, użyj lastval()

56

Jest to prosto z przepełnienie stos

Jak zauważyli @a_horse_w_nazwie i @Jack Douglas, currval działa tylko z bieżącą sesją. Jeśli więc zgadzasz się z faktem, że na wynik może mieć wpływ niezaangażowana transakcja innej sesji, a nadal chcesz czegoś, co będzie działać między sesjami, możesz użyć tego:

SELECT last_value FROM your_sequence_name;

Aby uzyskać więcej informacji, użyj łącza do SO).

Od dokumentacja Postgresa jednak jest wyraźnie zaznaczone, że

Błędem jest wywołanie lastval, jeśli nextval nie został jeszcze wywołany w bieżącej sesji.

Myślę więc, że mówiąc ściśle, aby właściwie użyć currval lub last_value dla sekwencji między sesjami, musisz zrobić coś takiego?

SELECT setval('serial_id_seq',nextval('serial_id_seq')-1);

Zakładając oczywiście, że nie będziesz mieć wstawki ani żadnego innego sposobu używania pola szeregowego w bieżącej sesji.

53
Slak

Ty musisz wywołać nextval dla tej sekwencji w tej sesji przed currval :

create sequence serial;
select nextval('serial');
 nextval
---------
       1
(1 row)

select currval('serial');
 currval
---------
       1
(1 row)

więc nie można znaleźć „ostatniego wstawionego identyfikatora” z sekwencji, chyba że insert zostanie wykonane w tej samej sesji (transakcja może zostać wycofana, ale sekwencja nie zostanie)

jak wskazano w odpowiedzi konia, create table z kolumną typu serial automatycznie utworzy sekwencję i użyje jej do wygenerowania domyślnej wartości dla kolumny, więc insert normalnie uzyskuje dostęp do nextval niejawnie:

create table my_table(id serial);
NOTICE:  CREATE TABLE will create implicit sequence "my_table_id_seq" for 
         serial column "my_table.id"

\d my_table
                          Table "stack.my_table"
 Column |  Type   |                       Modifiers
--------+---------+-------------------------------------------------------
 id     | integer | not null default nextval('my_table_id_seq'::regclass)

insert into my_table default values;
select currval('my_table_id_seq');
 currval
---------
       1
(1 row)

Istnieją więc pewne problemy z tymi różnymi metodami:

Currval pobiera tylko ostatnią wartość wygenerowaną w bieżącej sesji - co jest świetne, jeśli nie masz nic więcej generującego wartości, ale w przypadkach, w których możesz wywołać wyzwalacz i/lub ustawić sekwencję więcej niż raz w bieżącej transakcji, nie zwróci prawidłowej wartości. To nie jest problem dla 99% ludzi, ale należy to wziąć pod uwagę.

Najlepszym sposobem na przypisanie unikalnego identyfikatora po operacji wstawienia jest użycie klauzuli RETURNING. Poniższy przykład zakłada, że ​​kolumna powiązana z sekwencją nazywa się „id”:

insert into table A (cola,colb,colc) values ('val1','val2','val3') returning id;

Zauważ, że użyteczność klauzuli RETURNING wykracza daleko poza samo uzyskanie sekwencji, ponieważ:

  • Zwróć wartości, które były użyte dla „wstawienia końcowego” (po, na przykład, wyzwalacz PRZED mógł zmienić wstawiane dane).
  • Zwróć wartości, które zostały usunięte:

    usuń z tabeli A, gdzie zwracany jest identyfikator> 100 *

  • Zwróć zmodyfikowane wiersze po aktualizacji:

    aktualizacja tabeli Zestaw X = „y”, gdzie blah = „blech” powraca *

  • Użyj wyniku usunięcia do aktualizacji:

    Z A jako (usuń * z tabeli A jako zwracany identyfikator) aktualizacja B zestaw usunięty = prawda gdzie id w (wybierz identyfikator z A);

3
chander

Musisz GRANT użycie schematu, tak jak to:

GRANT USAGE ON SCHEMA schema_name to user;

i

GRANT ALL PRIVILEGES ON schema_name.sequence_name TO user;
1
AMML

Jeśli chcesz uzyskać wartość sekwencji bez wywołania nextval() i bez konieczności modyfikowania sekwencji, rzuciłem razem funkcję PL/pgSQL, aby ją obsłużyć: Znajdź wartość wszystkich sekwencje bazy danych

1
Christophe

Musiałem wykonać zapytanie pomimo użycia SQLALchemy, ponieważ nie udało mi się użyć currval.

nextId = db.session.execute("select last_value from <table>_seq").fetchone()[0] + 1

To był python flask + projekt postgresql).

1
Jalal

W PostgreSQL 11.2 sekwencję można traktować jak tabelę:

Przykład, jeśli masz sekwencję o nazwie: „names_id_seq”

select * from names_id_seq;
 last_value | log_cnt | is_called
------------+---------+-----------
          4 |      32 | t
(1 row)

To powinno dać ci ostatni wstawiony identyfikator (w tym przypadku 4), co oznacza, że ​​bieżąca wartość (lub wartość, która powinna być użyta dla id dalej) powinna wynosić 5.

0
scifisamurai