主 ID 序列不递增

Primary id sequence not incrementing

我有一个 table 设置如下:

USERS_TABLE = \
        Table("users", META_DATA,
              Column("id", Integer, Sequence("user_id_seq"), primary_key=True),
              Column("first_name", String(255)),
              Column("last_name", String(255))
             )

我可以像这样插入 单行

INS_EXPRESSION = insert(USERS_TABLE)
SEQ = Sequence('user_id_seq')
INS_EXPRESSION.values(first_name="Foo", last_name="Bar")

但是,如果我尝试 第二次插入 ,我会收到此错误:

sqlalchemy.exc.IntegrityError: (psycopg2.IntegrityError) null value in column "id" violates not-null constraint
DETAIL:  Failing row contains (null, null, null).
 [SQL: 'INSERT INTO users DEFAULT VALUES']

如何使 user_id_seq 序列 自动递增

问题是 Table object definition gives us next CREATE TABLE 语句的当前版本

CREATE TABLE users (
    id INTEGER NOT NULL, 
    first_name VARCHAR(255), 
    last_name VARCHAR(255), 
    PRIMARY KEY (id)
)

虽然它可能应该是

  1. 这个

    CREATE TABLE users (
        id INTEGER DEFAULT nextval('user_id_seq') NOT NULL, 
        first_name VARCHAR(255), 
        last_name VARCHAR(255), 
        PRIMARY KEY (id)
    )
    
  2. 或者只是这个

    CREATE TABLE users (
        id SERIAL NOT NULL, 
        first_name VARCHAR(255), 
        last_name VARCHAR(255), 
        PRIMARY KEY (id)
    )
    

所以每个语句的解决方案是:

  1. this recipe之后我们可以将server_default设置为序列的nextval like

    from sqlalchemy import (MetaData, Table, Column,
                            Integer, String, Sequence,
                            create_engine,
                            insert)
    
    
    db_uri = 'postgresql://username:password@hostname:5432/database'
    engine = create_engine(db_uri)
    META_DATA = MetaData(bind=engine)
    user_id_seq = Sequence("user_id_seq", metadata=META_DATA)
    USERS_TABLE = Table("users", META_DATA,
                        Column("id", Integer, user_id_seq,
                               server_default=user_id_seq.next_value(),
                               primary_key=True),
                        Column("first_name", String(255)),
                        Column("last_name", String(255)))
    USERS_TABLE.create(checkfirst=True)
    INS_EXPRESSION = insert(USERS_TABLE).values(first_name="Foo", last_name="Bar")
    engine.execute(INS_EXPRESSION)
    engine.execute('INSERT INTO users DEFAULT VALUES')
    
  2. 如果使用Sequence is not crucial than we can remove it and just set autoincrement flag to True (it will also work with Sequence removed without setting flag because

    ... SQLAlchemy will automatically set the first Integer PK column that's not marked as a FK as autoincrement=True...

    但它会更好,因为它更多 explicit):

    from sqlalchemy import MetaData, Table, Column, Integer, String, create_engine, insert
    
    db_uri = 'postgresql://username:password@hostname:5432/database'
    engine = create_engine(db_uri)
    META_DATA = MetaData(bind=engine)
    
    USERS_TABLE = Table("users", META_DATA,
                        Column("id", Integer,
                               autoincrement=True,
                               primary_key=True),
                        Column("first_name", String(255)),
                        Column("last_name", String(255)))
    USERS_TABLE.create(checkfirst=True)
    
    INS_EXPRESSION = insert(USERS_TABLE).values(first_name="Foo", last_name="Bar")
    engine.execute(INS_EXPRESSION)
    engine.execute('INSERT INTO users DEFAULT VALUES')
    

我更喜欢第二个,因为使用 Sequence 看起来像 YAGNI


P. S.

顺便问一下,你为什么要用 UPPER_CASE 的名字?这些对象看起来不像 constants to me since you can mutate them freely (PEP-8)