it-swarm-eu.dev

Jak mohu použít Currval () v PostgreSQL k získání posledního vloženého id?

Mám stůl:

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

Z této tabulky chci „poslední vložené ID“, bez použití RETURNING id Na vložení. Zdá se, že existuje funkce CURRVAL() , ale nechápu, jak ji používat.

Zkoušel jsem s:

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

ale žádný z nich nefunguje. Jak mohu použít currval() k získání posledního vloženého id?

70
Jonas

Pokud vytvoříte sloupec jako serial PostgreSQL automaticky vytvoří sekvenci.

Název sekvence je automaticky generován a je vždy tablename_columnname_seq, ve vašem případě bude posloupnost jmen names_id_seq.

Po vložení do tabulky můžete zavolat currval() s tímto názvem sekvence:

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=>

Místo pevného kódování názvu sekvence můžete místo toho použít pg_get_serial_sequence():

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

Tímto způsobem se nemusíte spoléhat na strategii pojmenování, kterou používá Postgres.

Nebo pokud vůbec nechcete používat název sekvence, použijte lastval()

56

To je přímo z Stack Overflow

Jak na to poukázali @a_horse_with_no_name a @ Jack Douglas, Currval pracuje pouze s aktuální relací. Takže pokud jste v pořádku se skutečností, že výsledek může být ovlivněn nepotvrzenou transakcí jiné relace a stále chcete něco, co bude fungovat v rámci relací, můžete použít toto:

SELECT last_value FROM your_sequence_name;

Použijte odkaz k SO pro více informací.

Z dokumentace Postgres je však jasně uvedeno, že

Je chybou volat lastval, pokud nextval ještě nebyl vyvolán v aktuální relaci.

Takže si myslím, že striktně mluvím, abych správně použil Currval nebo last_value pro sekvenci napříč relacemi, musel bys něco udělat?

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

Za předpokladu, že v aktuální relaci nebudete mít vložený nebo jiný způsob využití sériového pole.

53
Slak

Vy musíte zavolat nextval pro tuto sekvenci v této relaci před currval :

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

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

takže nemůžete najít 'poslední vložené id' ze sekvence, pokud insert není provedeno ve stejné relaci (transakce se může vrátit zpět, ale sekvence nebude)

jak je uvedeno v odpovědi a_horse, create table se sloupcem typu serial automaticky vytvoří sekvenci a použije ji ke generování výchozí hodnoty pro sloupec, takže insert normálně přistupuje k nextval implicitně:

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)

S těmito různými metodami tedy existují problémy:

Currval získá pouze poslední hodnotu vygenerovanou v aktuální relaci - což je skvělé, pokud nemáte žádné další hodnoty generující hodnoty, ale v případech, kdy byste mohli volat trigger a/nebo nechat posunout sekvenci více než jednou v aktuální transakci, je to nevrátí správnou hodnotu. To není problém pro 99% lidí tam venku - ale je to něco, co bychom měli vzít v úvahu.

Nejlepší způsob, jak získat jedinečný identifikátor po operaci vložení, je použití klauzule RETURNING. Následující příklad předpokládá, že sloupec vázaný na sekvenci se nazývá „id“:

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

Všimněte si, že užitečnost klauzule RETURNING jde mnohem dále, než jen získání posloupnosti, protože bude také:

  • Vraťte hodnoty, které byly použity pro „konečnou vložení“ (například poté, co mohl SPUŠTĚNÍ před změnou vložených dat změnit).
  • Vraťte odstraněné hodnoty:

    smazat z tabulky A, kde id> 100 se vrací *

  • Po UPDATE vrátit upravené řádky:

    aktualizační tabulka A sada X = 'y', kde blah = 'blech' vracející se *

  • Pro aktualizaci použijte výsledek smazání:

    WITH A as (smazat * z tabulky A jako návratové id) aktualizace B set odstraněn = true, kde id in (vyberte id z A);

3
chander

Je třeba GRANT použití ve schématu, jako je tato:

GRANT USAGE ON SCHEMA schema_name to user;

a

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

Pokud chcete získat hodnotu sekvencí, aniž byste volali nextval(), a aniž byste museli sekvenci upravovat, hodil jsem dohromady funkci PL/pgSQL, abych ji zvládl: Najděte hodnotu všech sekvence databáze

1
Christophe

Musel jsem provést dotaz i přes použití SQLALchemy, protože jsem nebyl úspěšný při používání Currval.

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

Jednalo se o python flask + projekt postgresql).

1
Jalal

V PostgreSQL 11.2 můžete posloupnost považovat za tabulku, jak se zdá:

Příklad, pokud máte sekvenci s názvem: 'names_id_seq'

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

To by vám mělo dát poslední vložené ID (v tomto případě 4), což znamená, že aktuální hodnota (nebo hodnota, která by měla být použita pro následující ID) by měla být 5.

0
scifisamurai