我在模型中使用 NUMMULTIRANGE 字段。 PostgreSQL 在docs中描述了这种类型的函数。但我在 SQLAlchemy 中找不到此功能的实现。我已阅读文档的这part。 Range 类型有很多有用的属性,但 Multirange 没有。
我的模型看起来像:
...
from sqlalchemy.dialects.postgresql import Range
from sqlalchemy.dialects.postgresql import NUMMULTIRANGE
class Condition(Base):
range: Mapped[list[Range[Decimal]]] = mapped_column(NUMMULTIRANGE)
有没有办法使用 PostgreSQL 内置函数进行多范围?例如,我想找到多范围的下限和上限,或者使用函数 lower_inc、lower_inf。在这种情况下,似乎我必须迭代我的范围列表。也许您可以建议更有效的方法,或者我错过了文档中的某些内容。
我正在使用 SQLAlchemy 2.0.28 和 PostgreSQL 15。
还有一个问题:PostgreSQL中的Range类型是否有可能定义不包含一个值的Range,相当于
!=
表达式?它允许我拒绝使用多范围,因为我必须使用多范围 x != 6
?指定像
'{(,6),(6,)}'
这样的表达式
您所要求的几乎已使用
func
完成。我添加了一些功能,我相信这些功能应该足以让其他人工作。
我已经展示了一些断言语句,这些语句在空表上将是正确的。
from decimal import Decimal
from sqlalchemy import DECIMAL, cast, create_engine, func, select
from sqlalchemy.dialects.postgresql import NUMMULTIRANGE, Range
from sqlalchemy.dialects.postgresql.ranges import MultiRange
from sqlalchemy.orm import DeclarativeBase, Mapped, Session, mapped_column
class Base(DeclarativeBase):
pass
class Condition(Base):
__tablename__ = "condition"
id: Mapped[int] = mapped_column(primary_key=True)
range: Mapped[MultiRange[Decimal]] = mapped_column(NUMMULTIRANGE)
engine = create_engine("postgresql+psycopg://username:password@localhost/database")
Base.metadata.create_all(engine)
with Session(engine) as session:
session.add(Condition(range=[Range(Decimal(7), Decimal(10)), Range(Decimal(-1), Decimal(6))]))
session.add(Condition(range=[Range()]))
session.add(Condition(range=[Range(empty=True)]))
session.commit()
with Session(engine) as session:
upper = session.scalar(select(func.upper(Condition.range)).where(Condition.id == 1))
assert upper == 10
lower = session.scalar(select(func.lower_inf(Condition.range)).where(Condition.id == 2))
assert lower is True
is_empty = session.scalar(select(func.isempty(Condition.range)).where(Condition.id == 3))
assert is_empty is True
count = session.scalar(select(func.count()).where(Condition.range.op("@>")(MultiRange([Range(Decimal(7), Decimal(10))]))))
assert count == 2
count = session.scalar(select(func.count()).where(cast(0, DECIMAL).op("<@")(Condition.range)))
assert count == 2
对于你的“附加问题”,我不是 Postgres 专家,我无法获得任何关于如何做到这一点的可靠线索。当然,这并不意味着不可能。