简体   繁体   中英

Having two serial keys in postgresql via sqlalchemy

I have an unusual challenge. I'm modifying a table to be able to join with two other legacy groups of PostgreSQL tables.

One group pretty much requires that each record in the table have a unique integer. So, the following field definition would work:

numeric_id = sql.Column(sql.Integer, primary_key=True)

The other group of tables all use UUID fields for the expected JOIN requests. So the following field definition would work:

uu_account_id = sql.Column(UUID(as_uuid=True), primary_key=True)

But, clearly, I can't have two primary keys. So one of them needs to not be a primary key. It would be nice to simply have both still be automatically assigned when a new record is made.

Any suggestions?

I'm sure I can do a quick hack, but I'm curious if there is a nice clean answer.

(And no: changing the other tables is NOT an option. Way too much legacy code.)

Make the uuid column the primary key, like usual.

Define the other column as having serial type and unique . In SQL I'd write

create table mytable (
    mytable_id uuid primary key default uuid_generate_v4(),
    mytable_legacy_id serial unique not null,
    ... other cols ...
);

so you just need to do the SQLAlchemy equivalent, whatever that is, of a not null , unique field.

Note that "serial" is just shorthand for

create sequence tablename_colname_seq;
create table tablename (
    colname integer default nextval('tablename_colname_seq'),
    ... cols ...
);
alter sequence tablename_colname_seq owned by tablename.colname;

so if you can't make sqlalchemy recognise that you can have a serial field that isn't a primary key, you can do it this way instead.

Between the SQLAlchemy, alembic (which I also use), and PostgreSQL, this turned out to be tricky.

If creating a brand new table from scratch, the following works for my numeric_id column:

numeric_id = sql.Column(sql.Integer, sql.Sequence('mytable_numeric_id_seq'), unique=True, nullable=False)

(It is possible that the unique=True and nullable=False are overkill.)

However, if modifying an existing table, the sequence itself fails to get created. Or, at least, I couldn't get it to work.

The sequence can be created by hand, of course. Or, if using 'alembic' to make distributed migrations easier, add:

from sqlalchemy.schema import Sequence, CreateSequence

def upgrade():
    op.execute(CreateSequence(Sequence("mytable_numeric_id_seq")))

To the version script created by alembic.

Special thanks to Craig for his help.

(Note: most of the SQLAlchemy examples on the net use db. as the module alias rather than sql. . Same thing really. I used sql. simply because I'm using db. already for MongoDB.)

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM