SQLAlchemy创建拼接两列的Computed列提示表达式非不可变如何解决
PostgreSQL生成列报错
generation expression is not immutable的解决方法 错误原因
这个报错是PostgreSQL的原生限制:存储生成列(STORED GENERATED COLUMN)的计算表达式必须是immutable类型,即相同输入永远返回相同输出、不受任何外部配置(比如本地化规则、时区等)影响。
你两种写法触发报错的原因分别是:
concat()函数本身属性为stable而非immutable,不符合生成列要求- 用
||运算符拼接时,source是文本类型、source_id是整数类型,拼接时会触发隐式类型转换,该转换过程不是immutable,因此哪怕用||运算符仍然会报错
解决方案
方案1:修改生成列表达式,显式做类型转换
将source_id显式转换为文本类型,让拼接操作使用immutable的文本拼接函数即可:
id = Column(Text, Computed("source || CAST(source_id AS TEXT)"), primary_key=True)
修改后生成的SQL符合PostgreSQL要求,可正常建表。
方案2:用SQLAlchemy混合属性替代数据库生成列
如果不想依赖数据库的生成列特性,可以把拼接逻辑放到应用层实现,同时额外加联合唯一约束保证source和source_id的唯一性:
from sqlalchemy import UniqueConstraint from sqlalchemy.ext.hybrid import hybrid_property from sqlalchemy import Column, Integer, Text from sqlalchemy.ext.declarative import declarative_base Base = declarative_base() class Product(Base): __tablename__ = "product" source = Column(Text, nullable=False) source_id = Column(Integer, nullable=False) name = Column(Text, nullable=True) # 联合唯一约束保证source和source_id组合唯一 __table_args__ = ( UniqueConstraint('source', 'source_id', name='uq_product_source_source_id'), ) # 应用层拼接生成id,不需要数据库计算 @hybrid_property def id(self): return f"{self.source}{self.source_id}"
这种方案兼容性更强,不受数据库生成列的各种限制,性能也更好。
备选方案
如果你只需要API调用时有单列唯一id,也可以直接用自增整数作为主键,仅增加source和source_id的联合唯一约束即可,逻辑更简单,性能也更高:
class Product(Base): __tablename__ = "product" id = Column(Integer, primary_key=True, autoincrement=True) source = Column(Text, nullable=False) source_id = Column(Integer, nullable=False) name = Column(Text, nullable=True) __table_args__ = ( UniqueConstraint('source', 'source_id', name='uq_product_source_source_id'), )
内容的提问来源于stack exchange,提问作者Karol Zlot
相关产品推荐
相关产品推荐

