SQLAlchemy 多类型列 - 混合 属性 查询
SQLAlchemy Multitype columns - Hybrid Property querying
我的 PostgreSQL 数据库中有几个 table 需要包含时间序列,例如 IoT-link 上下文中的信息,这需要为系列,像这样:
class Telemetry(Base):
__tablename__ = "ts_kv"
key = Column(Integer, primary_key=True)
bool_v = Column(Boolean)
str_v = Column(String)
long_v = Column(BigInteger)
dbl_v = Column(DOUBLE_PRECISION)
json_v = Column(JSON)
ts = Column(BigInteger, primary_key=True)
entity_id = Column(UUID(as_uuid=True), nullable=False, primary_key=True)
我需要解析来自 REST API 的传入模型,该模型具有单个 value 字段,可以是上述任何类型。我可以毫无问题地将输入数据类型正确解析到相应的列中。
当我尝试为给定的 值 查询 table 时出现问题,而不直接指定数据类型,我需要实现这样的操作:
data = session.query(Telemetry.ts, Telemetry.value).filter(Telemetry.value == MY_MULTITYPE_VALUE).all()
我试过使用混合属性和混合方法,如下所示:
@hybrid_property
def value(self):
return self.str_v if self.str_v else (
self.dbl_v if self.dbl_v else (
self.bool_v if self.bool_v else (
self.json_v if self.json_v else self.long_v
)
)
)
@value.expression
def value(self):
return self.str_v if self.str_v else (
self.dbl_v if self.dbl_v else (
self.bool_v if self.bool_v else (
self.json_v if self.json_v else self.long_v
)
)
)
第一部分操作正确,就像我查询:
session.query(Telemetry.value).filter(ANY FILTER).all()
我确实得到了正确的值。但是,如下例中的查询失败,因为 expression for value 对于条件的第一部分总是计算 true,即:if self.str_v 总是产生 True,因为它将 COLUMN 评估为存在,而不是该列中行的实际值。我还尝试使用 func 和 not_/is_null 运算符同样的结果。
a = session.query(Telemetry).filter(Telemetry.value == 55).first() #Always fails because long_v is behind in the expression evaluation.
我怎样才能以最简单的方式实现这种行为?我研究了复合列,但无法找到正确处理 parsing/de-parsing.
的方法
正如@rfkortekaas 在他的评论中正确指出的那样,表达式 需要是SQL。而if/else不符合条件。
from sqlalchemy import case
@hybrid_property
def value(self):
return self.str_v if self.str_v is not None else (
self.long_v if self.long_v is not None else (
self.dbl_v if self.dbl_v is not None else self.bool_v
)
)
@value.expression
def value(cls):
return case(
(cls.str_v.is_not(None), cls.str_v),
(cls.dbl_v.is_not(None), cls.dbl_v),
(cls.long_v.is_not(None), cls.long_v),
else_=cls.bool_v
)
我的 PostgreSQL 数据库中有几个 table 需要包含时间序列,例如 IoT-link 上下文中的信息,这需要为系列,像这样:
class Telemetry(Base):
__tablename__ = "ts_kv"
key = Column(Integer, primary_key=True)
bool_v = Column(Boolean)
str_v = Column(String)
long_v = Column(BigInteger)
dbl_v = Column(DOUBLE_PRECISION)
json_v = Column(JSON)
ts = Column(BigInteger, primary_key=True)
entity_id = Column(UUID(as_uuid=True), nullable=False, primary_key=True)
我需要解析来自 REST API 的传入模型,该模型具有单个 value 字段,可以是上述任何类型。我可以毫无问题地将输入数据类型正确解析到相应的列中。
当我尝试为给定的 值 查询 table 时出现问题,而不直接指定数据类型,我需要实现这样的操作:
data = session.query(Telemetry.ts, Telemetry.value).filter(Telemetry.value == MY_MULTITYPE_VALUE).all()
我试过使用混合属性和混合方法,如下所示:
@hybrid_property
def value(self):
return self.str_v if self.str_v else (
self.dbl_v if self.dbl_v else (
self.bool_v if self.bool_v else (
self.json_v if self.json_v else self.long_v
)
)
)
@value.expression
def value(self):
return self.str_v if self.str_v else (
self.dbl_v if self.dbl_v else (
self.bool_v if self.bool_v else (
self.json_v if self.json_v else self.long_v
)
)
)
第一部分操作正确,就像我查询:
session.query(Telemetry.value).filter(ANY FILTER).all()
我确实得到了正确的值。但是,如下例中的查询失败,因为 expression for value 对于条件的第一部分总是计算 true,即:if self.str_v 总是产生 True,因为它将 COLUMN 评估为存在,而不是该列中行的实际值。我还尝试使用 func 和 not_/is_null 运算符同样的结果。
a = session.query(Telemetry).filter(Telemetry.value == 55).first() #Always fails because long_v is behind in the expression evaluation.
我怎样才能以最简单的方式实现这种行为?我研究了复合列,但无法找到正确处理 parsing/de-parsing.
的方法正如@rfkortekaas 在他的评论中正确指出的那样,表达式 需要是SQL。而if/else不符合条件。
from sqlalchemy import case
@hybrid_property
def value(self):
return self.str_v if self.str_v is not None else (
self.long_v if self.long_v is not None else (
self.dbl_v if self.dbl_v is not None else self.bool_v
)
)
@value.expression
def value(cls):
return case(
(cls.str_v.is_not(None), cls.str_v),
(cls.dbl_v.is_not(None), cls.dbl_v),
(cls.long_v.is_not(None), cls.long_v),
else_=cls.bool_v
)