2012-09-18 76 views
15

Mi objetivo es hacer que se inserte automáticamente un campo de clave principal al insertar una nueva fila en la tabla.currval aún no se ha definido esta sesión, ¿cómo obtener secuencias de múltiples sesiones?

¿Cómo pasar una secuencia de una sesión a otra en 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

Todo el propósito de una secuencia es tenerla como sesión local. No puede "entregar" el currval a otra sesión. ¿Por qué crees que lo necesitas? ¿Por qué no hacer todo en una sola transacción? –

+0

@a_horse_with_no_name porque tengo dos sesiones abiertas al mismo tiempo: una de administrador y una de producción. Entonces tengo que tener dos sesiones separadas. –

+0

¿por qué no crear una secuencia única y luego simplemente compartirla entre las dos sesiones? Reciben identificaciones únicas, trabajo hecho. –

Respuesta

10

Esto puede ser más sencillo de lo que piensa ...

Mi objetivo es conseguir un campo de clave principal se inserta automáticamente cuando insertar nueva fila en la tabla.

acaba de establecer el valor predeterminado de la columna:

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

O más simple aún, crear la tabla con un tipo serial para la clave principal para empezar:

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

Se crea una secuencia dedicada y establece el valor predeterminado para tbl_id automáticamente.

De esta manera tbl_id se asigna automáticamente el siguiente valor de la secuencia adjunta si no lo menciona en el INSERT. Funciona con cualquier sesión, concurrente o no.

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

Si desea que el nuevo tbl_id volver a hacer algo con él:

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

El currval devolverá el último valor generado para la secuencia en la sesión actual. Entonces, si otra sesión genera un nuevo valor para la secuencia, aún puede recuperar el último valor generado por SU sesión, evitando errores.

Pero, para obtener el último valor generado en todas las sesiones, se puede utilizar la anterior:

SELECT last_value FROM your_sequence_name; 

tener cuidado, si el valor fue usado por otra sesión con una transacción uncommited (o abortada) y use este valor como referencia, puede recibir un error. En general, las personas solo necesitan el currval o incluso el retorno de setval.

+0

Cómo obtener el último valor generado por otra sesión. Si uso un cantante DB User, ¿afectará la precisión? – Volatil3

+0

Actionally Es interesante, ¿por qué la posibilidad de 'SELECT * FROM sequence' ni siquiera se menciona en la documentación oficial? – Eugene

1

En realidad nextval avanzará secuencia y devuelve el nuevo valor, por lo que sería la respuesta para su pregunta.

currval devolverá el valor más reciente obtenido con nextval para la secuencia especificada (aunque esto podría fallar si no se utiliza nextval en la sesión actual).

0

Este problema parece ser intermitente, Para mantener la coherencia utilizar CTE para conseguir secuencia insertada para la sesión actual

CON inserta AS ( INSERT INTO notifn_main (notifn_dt, stat_id) SELECT ahora(), 22 DE notifn ID DEVUELTO) SELECCIONE id desde insertado INTO tmp_id;

0

Voy a dar una respuesta práctica para este asunto. Mi servidor de base de datos es utilizado por mis programas y mi terminal psql; entonces hay múltiples sesiones Actualmente estoy en mi terminal 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) 

Parece que sólo se pueden ver los valores en su propia sesión. Esto también afectará el currval de otra sesión. Esto probablemente esté relacionado con el multi-threading del servidor para aislar diferentes sesiones. El contador (serial en psql) es un objeto compartido. En mi opinión, esta sesión debería ser capaz de obtener el valor actual del contador siempre que el contador esté bloqueado correctamente para asegurar que solo un hilo (sesión) pueda incrementarlo (operación atómica). Pero podría estar equivocado aquí (no es un experto en escritor de servidor de base de datos).

Cuestiones relacionadas