简体   繁体   English

SQLalchemy .filter 无法按预期工作

[英]SQLalchemy .filter does not work as expected

I have the following query:我有以下查询:

        question = Questions.query\
        .filter(Questions.quiz_id == quiz.id) \
        .filter(Responses.session_id == session[0].id) \
        .filter(Responses.question_id != Questions.id) \
        .order_by(Questions.category) \
        .order_by(func.rand()) \
        .first()

What it does is this:它的作用是这样的:

  1. Get a question from a DB从数据库中获取问题
  2. Make sure the question is from the correct quiz确保问题来自正确的测验
  3. Check which already answered questions are linked to this session in the responses table在响应表中检查哪些已经回答的问题与此会话相关联
  4. Make sure the next question is still unanswered (eg. the question ID is not yet in the responses table with the associated session_id linked to it)确保下一个问题仍未得到解答(例如,问题 ID 尚未在响应表中与关联的 session_id 链接)
  5. Order it by category (1 to 5)按类别排序(1 到 5)
  6. Pick a random question from the first category in the list从列表中的第一个类别中随机选择一个问题

This all works fine only when there is already an answer in the responses table.只有当响应表中已经有答案时,这一切才能正常工作。 However, when this is the first question to be answered, it returns None.但是,当这是要回答的第一个问题时,它返回 None。 I suspect this is because it can't find the session_id in the responses table.我怀疑这是因为它在响应表中找不到 session_id。 So this line is probably the cause:所以这一行可能是原因:

.filter(Responses.session_id == session[0].id) \

Unfortunately, I have no clue about the solution here.不幸的是,我对这里的解决方案一无所知。 It's not in the ordering, because when I just comment out those lines, it produces the same result.它不在排序中,因为当我注释掉这些行时,它会产生相同的结果。 Secondary, when I produce the raw MySQL query, it works by joining the two tables on question_id == question.id and session_id == session.id .其次,当我生成原始 MySQL 查询时,它通过连接question_id == question.idsession_id == session.id上的两个表来工作。 So in MySQL, this problem does not occur.所以在MySQL中,不会出现这个问题。 This strengthens my believe the problem is in the .filter option.这让我更加相信问题出在 .filter 选项中。

The workaround in place right now is first checking whether there is a row in the responses table with the current session_id in it.现在的解决方法是首先检查响应表中是否有包含当前 session_id 的行。 If not, I know it's the first question and just leave out the .filter on session_id .如果没有,我知道这是第一个问题,只需.filter session_id上的.filter This works but is an extra call which I assume is unnecessary.这有效,但我认为是不必要的额外调用。

Please help me out, thanks in advance.请帮助我,提前致谢。

Your analysis is correct, the problem is caused by the .filter() clause there.您的分析是正确的,问题是由那里的.filter()子句引起的。 I'd rewrite the query to use a WHERE NOT EXISTS .我会重写查询以使用WHERE NOT EXISTS This means that if there is no response matching the Question, it is still returned.这意味着如果没有与问题匹配的响应,它仍然会被返回。

responses_this_session = Response.query\
    .filter(Responses.session_id == session[0].id)

question = Questions.query\
        .filter(Questions.quiz_id == quiz.id) \
        .filter(~exists(
            responses_this_session
            .filter(Responses.question_id == Questions.id)
        ))
        .order_by(Questions.category) \
        .order_by(func.rand()) \
        .first()

Or equivalently:或等效地:

question = Questions.query\
        .filter(Questions.quiz_id == quiz.id) \
        .filter(
            ~exists().where(
                and_((Responses.session_id == session[0].id),
                     (Responses.question_id == Questions.id))
            )
        )
        .order_by(Questions.category) \
        .order_by(func.rand()) \
        .first()

The matching SQL:匹配的 SQL:

SELECT questions.*
FROM questions
WHERE quiz_id = 12
AND NOT EXISTS(
  SELECT *
  FROM responses
  WHERE session_id = 'my_session_id'
    AND responses.question_id = questions.id
)
ORDER BY category, RAND()

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM