我有三个模型(注意这是在Flask-SQLAlchemy中完成的,但是如果你只能为vanilla SQLAlchemy写一个答案,那对我来说没问题。)为了清楚起见,删除了不相关的字段。
class KPI(db.Model):
__tablename__ = 'kpis'
id = db.Column(db.Integer, primary_key=True)
identifier = db.Column(db.String(length=50))
class Report(db.Model):
__tablename__ = 'reports'
id = db.Column(db.Integer, primary_key=True)
class ReportKPI(db.Model):
report_id = db.Column(db.Integer, db.ForeignKey('reports.id'), primary_key=True)
kpi_id = db.Column(db.Integer, db.ForeignKey('kpis.id'), primary_key=True)
report = db.relationship('Report', backref=db.backref('values'))
kpi = db.relationship('KPI')
我的目标是查找不衡量特定Report
的所有KPI
个对象(即没有ReportKPI
个KPI
关系identifier
的对象设置为特定值。)
我的一次尝试看起来像
Report.query \
.join(ReportKPI) \
.join(KPI) \
.filter(KPI.identifier != 'reflection')
但这会返回更多实际存在的Report
个对象(我想每ReportKPI
有一个KPI
除了“反射”以外的任何对象。)
我想用SQLAlchemy实现的目标是什么?如果是这样,什么是神奇的词(请求似乎不起作用......)
答案 0 :(得分:2)
EXISTS子查询表达式非常适合您的目标。编写此类查询的简便方法是:
Report.query.\
filter(db.not_(Report.values.any(
ReportKPI.kpi.has(identifier='reflection'))))
但这产生了2个嵌套的EXISTS表达式,尽管EXISTS中的连接也可以:
Report.query.\
filter(db.not_(
ReportKPI.query.
filter_by(report_id=Report.id).
join(KPI).
filter_by(identifier='reflection').
exists()))
最后,带有IS NULL的LEFT JOIN也是一个选项:
Report.query.\
outerjoin(db.join(ReportKPI, KPI),
db.and_(ReportKPI.report_id == Report.id,
KPI.identifier == 'reflection')).\
filter(KPI.id.is_(None))