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?
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()
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.
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 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);
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;
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
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).
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.