如果您绝对无法更改架构,那么您可以取消透视性能数据并加入用户。关系的示例映射,因为没有提供:
In [2]: class User(Base):
...: __tablename__ = "users"
...: username = Column(Unicode(255), primary_key=True)
...: firstname = Column(Unicode(255))
...: lastname = Column(Unicode(255))
...:
In [3]: class Performance(Base):
...: __tablename__ = "performance"
...: timestamp = Column(Date, primary_key=True)
...: # NOTE: this works **only** in a class body context,
...: # and your schema shouldn't be like this anyway.
...: for name in ['alice', 'bob']:
...: locals()[name] = Column(Integer, nullable=False)
...:
使用检查获取具有性能数据的用户名。您还可以保留用户名的静态列表:
In [11]: users = inspect(Performance).attrs.keys()[1:]
In [12]: users
Out[12]: ['alice', 'bob']
形成unpivot 查询——这只是一种方法:
In [15]: from sqlalchemy.dialects import postgresql
...: performance = session.query(
...: func.unnest(postgresql.array(users)).label('username'),
...: func.unnest(postgresql.array(
...: [getattr(Performance, name)
...: for name in users])).label('value')).\
...: filter(Performance.timestamp == '2017-11-2').\
...: subquery()
...:
将用户与他们的绩效价值联系起来:
In [24]: session.query(User, performance.c.value).\
...: join(performance, performance.c.username == User.username).\
...: all()
Out[24]:
[(<__main__.User at 0x7f79eb5d2c88>, 1),
(<__main__.User at 0x7f79eb5d2cf8>, 5)]
如果您要更改架构以将性能数据存储为(timestamp, username, value)
元组,您可以简单地执行以下操作:
In [2]: class User(Base):
...: __tablename__ = "users"
...: ...
...: performance = relationship("BetterPerformance")
...:
In [25]: class BetterPerformance(Base):
...: __tablename__ = "better_performance"
...: timestamp = Column(Date, primary_key=True)
...: username = Column(ForeignKey('users.username'), primary_key=True)
...: value = Column(Integer, nullable=False)
...:
In [13]: session.query(User, BetterPerformance.value).\
...: join(User.performance).\
...: filter(BetterPerformance.timestamp == '2017-11-2').\
...: all()
Out[13]:
[(<__main__.User at 0x7f6ae3282c18>, 1),
(<__main__.User at 0x7f6ae3282ba8>, 5)]
甚至:
In [17]: session.query(User).\
...: join(User.performance).\
...: options(contains_eager(User.performance)).\
...: filter(BetterPerformance.timestamp == '2017-11-2').\
...: all()
Out[17]: [<__main__.User at 0x7f6ae3282c18>, <__main__.User at 0x7f6ae3282ba8>]
In [18]: [u.performance[0].value for u in _]
Out[18]: [1, 5]