根据 SQLAlchemy 中的另一个值从连接中选择多个值

Selecting multiple values from a join depending on another value in SQLAlchemy

我在 SQLAlchemy 中有一个相当繁重的查询,我正在尝试对其进行一些优化,但我在连接方面遇到了困难,因为我不太了解它。我的小测试显示 selects 比连接慢 7 倍,因此它可能会大大提高速度。

以下是相关表格及其关系:

我基本上想阅读 SessionData.value 其中 SessionData.key 等于某物,来自 ActionInfo 的 select。

这是我目前做事的方式:

stmt = select(
    ActionInfo.id,
    select(SessionData.value).where(
        SessionData.key == 'username',
        SessionLink.data_id == SessionData.id,
        SessionLink.info_id == ActionInfo.session_id,
    ).label('username'),
    select(SessionData.value).where(
        SessionData.key == 'country',
        SessionLink.data_id == SessionData.id,
        SessionLink.info_id == ActionInfo.session_id,
    ).label('country'),
)

在做上面提到的速度测试时,我得到了一个单一的连接工作,但我显然通过这种方法仅限于 1 个值:

stmt = select(
    ActionInfo.id,
    SessionData.value.label('country')
).filter(
    SessionData.key == 'country'
).outerjoin(SessionInfo).outerjoin(SessionLink).outerjoin(SessionData)

我将如何调整它以结束这样的事情?

stmt = select(
    ActionInfo.id,
    select(SessionData.value).where(SessionData.key=='username').label('username'),
    select(SessionData.value).where(SessionData.key=='country').label('country'),
).outerjoin(SessionInfo).outerjoin(SessionLink).outerjoin(SessionData)

如果有帮助的话,这是 SQLAlchemy 生成的连接代码:

SELECT action_info.id
FROM action_info LEFT OUTER JOIN session_info ON session_info.id = action_info.session_id LEFT OUTER JOIN session_link ON session_info.id = session_link.info_id LEFT OUTER JOIN session_data ON session_data.id = session_link.data_id

作为旁注,我假设我想要一个左外连接,因为我仍然想包含任何缺少 SessionData 记录的记录。一旦我完成了这个工作,我将测试内部连接有什么不同以确保。

代码如下:

keys = ["username", "country", "gender"]
q = select(ActionInfo.id).join(SessionInfo)
for key in keys:
    SD = aliased(SessionData)
    SL = aliased(SessionLink)
    q = (
        q.outerjoin(SL, SessionInfo.id == SL.info_id)
        .outerjoin(SD, and_(SL.data_id == SD.id, SD.key == key))
        .add_columns(SD.value.label(key))
    )

是通用的,可以扩展到不同数量的字段,并且应该生成类似于下面的 SQL:

SELECT action_info.id,
       session_data_1.value AS username,
       session_data_2.value AS country,
       session_data_3.value AS gender

FROM   action_info

JOIN   session_info ON session_info.id = action_info.session_id

LEFT OUTER JOIN session_link AS session_link_1 ON session_info.id = session_link_1.info_id
LEFT OUTER JOIN session_data AS session_data_1 ON session_link_1.data_id = session_data_1.id
    AND session_data_1.key = :key_1

LEFT OUTER JOIN session_link AS session_link_2 ON session_info.id = session_link_2.info_id
LEFT OUTER JOIN session_data AS session_data_2 ON session_link_2.data_id = session_data_2.id
    AND session_data_2.key = :key_2

LEFT OUTER JOIN session_link AS session_link_3 ON session_info.id = session_link_3.info_id
LEFT OUTER JOIN session_data AS session_data_3 ON session_link_3.data_id = session_data_3.id
    AND session_data_3.key = :key_3