0

我正在使用 flask-sqlalchemy 和 Postgres DB 构建基于 Flask 的 API 应用程序。

  • usersDB中的表为每个用户保存一条记录。这张桌子的PK是username(这里没什么特别的)
  • performanceDB中的表保存用户性能。此表的 PK 是一个日期。此表中的每个用户都有一个名为 的列username。(我知道有人说这种结构并不理想——但它是不相关的要求所必需的)。

例子:

PK = "username", tablename = "users"

| username | firstname | lastname | 
-----------------------------------
| alice    | Alice     | Johns    |
| bob      | Bob       | Speed    |


PK = "timestamp", tablename = "performance"

| timestamp | alice | bob  | 
-----------------------------------
| 2017-11-2 | 1     | 5    |
| 2017-11-3 | 6     | 9    |

我使用 SQLAlchemy 访问users表。

我愿意创建 REST API,它将接收日期参数并返回所有用户的集合以及他们在该日期的表现。

什么是正确的 SQLAlchemy 查询,因此不会为每个用户单独选择性能值。

4

1 回答 1

0

如果您绝对无法更改架构,那么您可以取消透视性能数据并加入用户。关系的示例映射,因为没有提供:

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]
于 2018-01-02T11:11:12.323 回答