python - SQLAlchemy 查询所有子级匹配过滤器的父级
问题描述
我正在尝试创建一个 sqlalchemy 查询(flask-sqlalchemy),如果所有子项都匹配查询而不是 ANY,则该查询仅返回父对象。IE
(Parent
.query
.join(Child)
.filter(Child.column == True)
).all()
将返回所有具有任何子对象的父对象,column == True
我该如何编写它以使所有子对象都必须具有column == True
?
- - - - - - - - - - - - - - - - 更新 - - - - - - - - - ------------
上面的部分是从这个实际代码中抽象出来的。在哪里
家长 == 学生和孩子 == StudentApplication
模型层次结构如下:
用户 ---> 学生 ---> StudentApplication
我正在尝试检索有学生但尚未提交申请的用户,同时忽略至少有 1 名学生提交申请的用户。
def _active_student_query(statement=None):
import sqlalchemy as sa
statement = statement or _active_user_query()
statement = statement.join(Student).filter(Student.suspended == sa.false())
return statement
def users_without_submitted_applications(exclude_contacted=False):
import sqlalchemy as sa
from sqlalchemy.orm.util import AliasedClass
# AppAlias = AliasedClass(StudentApplication)
has_any_approved_app = sa.exists(
sa.select([])
.select_from(Student)
.where((StudentApplication.student_id == Student.id) &
(StudentApplication.flags.op('&')(AppFlags.SUBMITTED) > 0),
)
)
statement = _active_student_query()
statement = (statement
# .join(StudentApplication)
# .filter(User.students.any())
# has a student and no submitted applications
.filter(~has_any_approved_app)
# .filter(StudentApplication.flags.op('&')(AppFlags.SUBMITTED) == 0)
)
if exclude_contacted:
statement = (statement
.join(AlertPreferences)
.filter(AlertPreferences.marketing_flags.op('&')(MarketingFlags.NO_APP_PING) == 0)
)
from lib.logger import logger
logger.info(statement.sql)
return statement
这是它产生的 SQL
SELECT users.is_active, users.flags, users.created_on, users.updated_on, users.id
FROM users JOIN student ON users.id = student.user_id
WHERE users.is_active = true AND student.suspended = false AND NOT (EXISTS (SELECT
FROM student_application
WHERE student_application.student_id = student.id AND (student_application.flags & %(flags_1)s) > %(param_1)s))
解决方案
如果你正在寻找一个所有孩子都有的父母column = TRUE
,那么这相当于所有没有孩子的父母column = FALSE
。如果您使用 JOIN,您会遇到每个孩子而不是每个父母拥有一行的问题。因此,我建议WHERE EXISTS()
改用。像这样的查询可以解决问题:
SELECT *
FROM parent
WHERE NOT EXISTS(
SELECT
FROM child
WHERE child.parent_id = parent.id
AND child.column = FALSE
)
在 Flask-SQLAlchemy 中,这变成:
import sqlalchemy as sa
has_any_false_children = sa.exists(
sa.select([])
.select_from(Child)
.where((Child.parent_id == Parent.id) &
(Child.column == sa.false()))
)
Parent.query.filter(~has_any_false_children)
更新
既然你在谈论User
s 所有Student
s 都StudentApplication
完成了,我认为它应该变成
student_has_any_non_approved_app = sa.exists(
sa.select([])
.select_from(StudentApplication)
.where((StudentApplication.student_id == Student.id) &
(StudentApplication.flags.op('&')(AppFlags.SUBMITTED) > 0) &
((StudentApplication.flags.op('&')(AppFlags.APPROVED) == 0) |
(StudentApplication.flags.op('&')(AppFlags.PARTIALLY_APPROVED) == 0)))
)
user_has_any_non_approved_students = sa.exists(
sa.select([])
.select_from(Student)
.where((Student.user_id == User.id) &
(Student.suspended == sa.false()) &
student_has_any_non_approved_app)
)
statement = (
_active_user_query()
.filter(User.students.any())
# has a student and no submitted applications
.filter(~user_has_any_non_approved_students)
)
这将返回所有用户。如果您随后想要该用户的学生,我会将其放入单独的查询中 - 并在那里应用营销标志。
statement = Student.query.filter(
Student.user_id.in_(user_ids),
Student.suspended == sa.false()
)
if exclude_contacted:
statement = (statement
.join(AlertPreferences)
.filter(AlertPreferences.marketing_flags.op('&')(MarketingFlags.NO_APP_PING) == 0)
)
推荐阅读
- docker - Docker Compose 正在运行,但浏览器中没有显示任何内容
- model-view-controller - 如何将过滤后的数据从 mvc.grid 导出到 excel 或 pdf
- gradle - gradle 添加依赖,如 npm
- node.js - 我需要有两个基于表列分组的数组响应,以便计数组对应于它的行
- javascript - Javascript - 根据另一个数组对对象数组进行排序
- vue.js - 未触发 Vuejs 指令中 gsap.scrollTrigger 的更新
- regex - 通过正则表达式匹配方法获取第一个子字符串
- c# - WebView2:单击按钮以在 WebView 窗口中显示网站
- reactjs - 电子生成器中的图像问题
- html - 如何降低我网站的分辨率