Fondo:
La aplicación que estoy desarrollando actualmente está en transición de SQLite3 a PostgreSQL. Todos los datos se han migrado correctamente, usando el .dump
de la base de datos actual, cambiando todas las tablas del tipo
CREATE TABLE foo ( id INTEGER NOT NULL, bar INTEGER, ... PRIMARY KEY (id), FOREIGN KEY(bar) REFERENCES foobar (id), ... );
a
CREATE TABLE foo ( id SERIAL NOT NULL, bar INTEGER, ... PRIMARY KEY (id), FOREIGN KEY(bar) REFERENCES foobar (id) DEFERRABLE, ... );
y SET CONSTRAINTS ALL DEFERRED;
.
Desde que uso SQLAlchemy, esperaba que las cosas funcionaran bien a partir de ese momento, después de cambiar el engine
, por supuesto. Pero el problema parece ser el autoincremento de la clave primaria a un valor único en INSERT
.
La tabla, digamos foo
, actualmente tengo problemas con más de 7500 filas, pero el current value
la secuencia foo_id_seq
se establece en 5
(porque he intentado las inserciones cinco veces y todas han fallado).
Pregunta:
Así que ahora mi pregunta es que sin proporcionar explícitamente el id
, en la statement INSERT
, ¿cómo puedo hacer que Postgres asigne automáticamente un valor único al campo id
si foo
? O más específicamente, ¿la secuencia devuelve un valor único para ella?
Azúcar:
Consigue todo eso a través de la interfaz SQLAlchemy.
Detalles del entorno:
PD: Si alguien encuentra un título más apropiado para esta pregunta, edítelo.
Su PRIMARY KEY
debe definirse para utilizar una SEQUENCE
como DEFAULT
, ya sea a través del pseudo tipo SERIAL
:
CREATE TABLE blah ( id serial primary key, ... );
o una SEQUENCE
explícita:
CREATE SEQUENCE blah_id_seq; CREATE TABLE blah ( id integer primary key default nextval('blah_id_seq'), ... ); ALTER SEQUENCE blah_id_seq OWNED BY blah.id;
Esto se discute en la documentación de SQLAlchemy .
Puedes agregar esto a una tabla existente:
CREATE SEQUENCE blah_id_seq OWNED BY blah.id; ALTER TABLE blah ALTER COLUMN id SET DEFAULT nextval('blah_id_seq');
Si prefiere restaurar un volcado, agregue secuencias manualmente.
Si hay datos existentes que ha cargado directamente en las tablas con COPY
o similar, debe establecer el punto de inicio de la secuencia:
SELECT setval('blah_id_seq', max(id)+1) FROM blah;
Yo diría que es probable que el problema tenga que ver con su desarrollo en SQLite, luego hacer un volcado y restaurar ese volcado en PostgreSQL. SQLAlchemy espera crear el esquema por sí mismo con los valores predeterminados y las secuencias apropiadas.
Lo que te recomiendo que hagas es que SQLAlchemy cree una base de datos nueva y vacía. Voltee los datos para cada tabla desde la base de datos SQLite a CSV, luego COPY
esos datos en las tablas PostgreSQL. Finalmente, actualice las secuencias con setval
para que generen los valores apropiados.
De una forma u otra, deberá asegurarse de que se crean las secuencias apropiadas. Puede hacerlo mediante los tipos de pseudo-columna SERIAL
, o mediante la creación de SEQUENCE
manual y la configuración DEFAULT
, pero debe hacerlo. De lo contrario, no hay manera de asignar un ID generado a la tabla de una manera eficiente y segura para la concurrencia.
Utilizar
alter sequence foo_id_seq restart with 7600
debería darle 7601 la próxima vez que llame a la secuencia.
http://www.postgresql.org/docs/current/static/sql-altersequence.html
Y luego los valores posteriores. Solo asegúrese de reiniciarlo con un valor> la última ID.