文章目录
在使用SQLAlchemy的ORM做关联查询filter时出了一点问题,同时也暴露出对SQLAlchemy的DSL的一些漏洞。
现在要查询的Model是Submission
,Submission
有两个外键submitter_id
和problem_id
,分别关联User
和Problem
这两个Model。 然后查询时想要对Submission
的两个外键ModelUser
和Problem
的字段做filter,但是不需要加载这两个外键Model。
于是我写成了这样
1 2 3 4 5 6 7 8 session.query(Submission).options( joinedload("submitter" ), joinedload("problem" ) ).filter(User.username == "JZQT" ).all() session.query(Submission).options( joinedload("submitter" ), joinedload("problem" ) ).filter(Problem.remote_pid == "1000" ).all()
结果发现查询出来的Submission
对象并不满足这些限制条件。 生成的SQL语句如下
1 2 3 4 5 6 7 8 9 10 11 SELECT {Submission, User , Problem 的所有字段名}FROM {Submission, Problem 和 User 的数据表名}LEFT OUTER JOIN {User 数据表名} ON {User .id == Submission.submitter_id}LEFT OUTER JOIN {Problem数据表名} ON {Problem.id == Submission.problem_id}WHERE {User .username == "JZQT" }SELECT {Submission, User , Problem 的所有字段名}FROM {Submission, Problem 和 User 的数据表名}LEFT OUTER JOIN {User 数据表名} ON {User .id == Submission.submitter_id}LEFT OUTER JOIN {Problem数据表名} ON {Problem.id == Submission.problem_id}WHERE {Problem.remote_pid == "1000" }
很明显这样的SQL不符合我们“不需要加载这两个外键Model” 这个要求,因为它SELECT
了User
和Problem
。
实际上这样的SQL造成的效果是这样的
如果数据库中存在username
等于"JZQT"
的User
对象,那么你会查询出所有的Submission
。 同理,如果数据库中存在remote_pid
为"1000"
的Problem
对象,会查询出所有的Submission
。 如果不存在,也就是说User
或Problem
中没有满足where子句条件的对象,那么查询不出来Submission
。
这样的SQL查询当然不符合我们的要求。
经过一段时间的琢磨,终于发现了一个符合要求的方法。
1 2 3 4 5 session.query(Submission).join(Problem, User).filter(User.username == "JZQT" ).all() session.query(Submission).join(Problem, User).filter(Problem.remote_pid == "1000" ).all()
它生成的SQL语句如下
1 2 3 4 5 6 7 8 9 10 11 SELECT {Submission 的所有字段名}FROM {Submission数据表名}JOIN {Problem的数据表名} ON {Problem.id == Submission.problem_id}JOIN {User 的数据表名} ON {User .id == Submission.submitter_id}WHERE {User .username == "JZQT" }SELECT {Submission 的所有字段名}FROM {Submission数据表名}JOIN {Problem的数据表名} ON {Problem.id == Submission.problem_id}JOIN {User 的数据表名} ON {User .id == Submission.submitter_id}WHERE {Problem.remote_pid == "1000" }
暂时先用这个了。
从以上SQL也可以看出来,joinedload
默认是左外连接LEFT OUTER JOIN
的。 另外,对与SQLAlchemy的联表问题,我理解的不够,有漏洞。 数据库SQL其实也不熟悉。
看来还是要好好学习一下才行。