2012-09-18 28 views
15

Il mio obiettivo è ottenere automaticamente un campo chiave primaria inserito quando si inserisce una nuova riga nella tabella.currval non è stato ancora definito questa sessione, come ottenere sequenze multisessione?

Come ottenere una sequenza da una sessione all'altra in PostgreSQL?

[email protected]:/home/yves$ psql -d test 
Mot de passe : 
psql (8.4.13) 
Saisissez « help » pour l''aide. 

test=> create sequence test001 start 10; 
CREATE SEQUENCE 
test=> select currval('test001'); 
ERREUR: la valeur courante (currval) de la séquence « test00 » n''est pas encore définie dans cette session 
--- current value not yet defined this session (???) 
test=> select setval('test001', 10); 
setval 
-------- 
     10 
(1 ligne) 

test=> select currval('test00'); 
    currval 
--------- 
     10 
(1 ligne) 

test=> \q 
[email protected]:/home/yves$ psql -d test 
Mot de passe : 
psql (8.4.13) 
Saisissez « help » pour l''aide. 

test=> select currval('test001'); 
ERREUR: la valeur courante (currval) de la séquence « test00 » n''est pas encore définie dans cette session 
+0

Lo scopo di una sequenza è di avere una sessione locale. Non è possibile "consegnare" il currval a un'altra sessione. Perché pensi che ne hai bisogno? Perché non fare tutto in un'unica transazione? –

+0

@a_horse_with_no_name perché ho due sessioni aperte contemporaneamente: una amministratore e una di produzione. Quindi devo avere due sessioni separate. –

+0

perché non creare una singola sequenza e quindi condividerla tra le due sessioni? Ricevono id unici, lavoro svolto. –

risposta

10

Questo può essere più semplice di quanto si pensi ...

Il mio obiettivo è quello di ottenere un campo chiave primaria inserita automaticamente quando si inserisce nuova riga nella tabella.

Basta impostare il valore predefinito della colonna:

ALTER TABLE tbl ALTER COLUMN tbl_id SET DEFAULT nextval('my_seq'::regclass); 

O più semplice ancora, creare la tabella con un tipo serial per la chiave primaria per cominciare:

CREATE TABLE tbl(
    tbl_id serial PRIMARY KEY 
,col1 txt 
    -- more columns 
); 

crea un sequenza dedicata e imposta automaticamente il valore predefinito per tbl_id.

In questo modo tbl_id viene assegnato automaticamente il valore successivo dalla sequenza collegata se non lo si specifica nello INSERT. Funziona con qualsiasi sessione, concomitante o meno.

INSERT INTO tbl(col1) VALUES ('foo'); 

Se si desidera che la nuova tbl_id torna a fare qualcosa con esso:

INSERT INTO tbl(col1) VALUES ('foo') RETURNING tbl_id; 
59

Il currval restituirà l'ultimo valore generato per la sequenza all'interno della sessione corrente. Quindi, se un'altra sessione genera un nuovo valore per la sequenza, è comunque possibile recuperare l'ultimo valore generato dalla TUA sessione, evitando errori.

Ma, per ottenere l'ultimo valore generato su tutte le sessioni, è possibile utilizzare il sopra:

SELECT last_value FROM your_sequence_name; 

attenzione, se il valore è stato utilizzato da altra sessione con una transazione UNCOMMITED (o interrotta) e si usa questo valore come riferimento, potresti ricevere un errore. Generalmente le persone hanno solo bisogno del currval o anche del ritorno di setval.

+0

Come ottenere l'ultimo valore generato da un'altra sessione. Se sto usando un utente DB cantante, ciò avrà comunque effetto sulla precisione? – Volatil3

+0

Operativamente È interessante, perché la possibilità di 'SELECT * FROM sequence' non è nemmeno menzionata nella documentazione ufficiale? – Eugene

1

realtà nextval avanzerà sequenza e restituire il nuovo valore, in modo che sarebbe la risposta per la tua domanda.

currval restituirà il valore più recente ottenuto con nextval per la sequenza specificata (Ciò potrebbe non riuscire se non ci fosse nextval utilizzato nella sessione corrente).

0

Questo problema sembra essere intermittente, per coerenza utilizzare CTE per ottenere sequenza inserita per la sessione corrente

CON inserito AS ( INSERT INTO notifn_main (notifn_dt, STAT_ID) SELEZIONE ora(), 22 DA notifn ID RESTITUZIONE) SELEZIONARE id da inserito INTO tmp_id;

0

Darò una risposta pratica a questo problema. Il mio server di database viene utilizzato dai miei programmi e dal mio terminale psql; quindi ci sono più sessioni. Attualmente mi trovo in mio terminale psql:

fooserver=> select currval('fusion_id_seq'); 
ERROR: currval of sequence "fusion_id_seq" is not yet defined in this session 
fooserver=> select nextval('fusion_id_seq'); 
nextval 
--------- 
    320032 
(1 row) 

fooserver=> select currval('fusion_id_seq'); 
currval 
--------- 
    320032 
(1 row) 

Sembra che si può vedere solo i valori nella propria sessione. Ciò influenzerà anche il valore di un'altra sessione. Questo è probabilmente correlato al multi-threading del server per isolare diverse sessioni. Il contatore (seriale in psql) è un oggetto condiviso. A mio avviso, questa sessione dovrebbe essere in grado di ottenere il valore corrente del contatore finché il contatore è correttamente bloccato per garantire che solo un singolo thread (sessione) possa incrementarlo (operazione atomica). Ma potrei sbagliarmi qui (non un esperto di database server writer).

Problemi correlati