Flask-SQLAlchemy 左外连接过滤查询
Posted
技术标签:
【中文标题】Flask-SQLAlchemy 左外连接过滤查询【英文标题】:Flask-SQLAlchemy Left Outer Join Filtered Query 【发布时间】:2016-05-08 16:14:11 【问题描述】:最初我试图做一个“右外连接”,但一旦我发现它不受支持,我就开始从左边开始工作。但是,我很难弄清楚如何写出我需要的东西。基本上我有两个表,Table_1
和Table_2
,我需要来自Table_1
的所有行,其中column_c
等于1
。此外,我需要来自Table_2
的所有行,其中column_b
尚未在Table 1
中。视觉上看起来像这样:
**Table_1**
column_a ( a and b are the
column_b ( primary key.
column_c
**Table_2**
column_b
这就是我在 SQL 中的写法:
SELECT *
FROM (SELECT * FROM Table_1 WHERE column_a = 123) t1
RIGHT OUTER JOIN Table_2 t2 ON t1.column_b = t2.column_b
WHERE t1.column_c = 1 or t1.column_c is NULL;
SELECT *
FROM Table_2 t2
LEFT OUTER JOIN (SELECT * FROM Table_1 WHERE column_a = 123) t1
ON Table_2 t2 ON t1.column_b = t2.column_b
WHERE t1.column_c = 1 or t1.column_c is NULL;
这是我在 Flask-SQLAlchemy 形式中所拥有的,重要的是要注意这是Table_2
的 db.Model 类中的一个方法。
def all_exclude(self, column_a):
return self.query.outerjoin(
Table_1,
Table_1.column_b==Table_2.column_b).filter(or_(
Table_1.column_c==None,
and_(Table_1.column_c==1,
Table_1.column_a==column_a))).all()
不幸的是,我在编写它时并没有考虑它,而且它不会真正起作用,因为我无法从类表单中调用该方法。我必须在初始化一个仅来自单行的查询后执行此操作,这不是我需要的。我知道我可以像这样将其作为查询运行:
Business.query.outerjoin(
Table_1,
Table_1.column_b==Table_2.column_b).filter(or_(
Table_1.column_c==None,
and_(Table_1.column_c==1,
Table_1.column_a==column_a))).all()
但是出于 OOP 的目的,我试图将我的类分开,但即使那样我也不认为这会起作用,因为从技术上讲,过滤器在加入之前没有完成。也许解决方案比我想象的要容易,但我不能完全理解它。提前谢谢!
【问题讨论】:
过度复杂是这里需要的词!首先,你为什么要这样写RIGHT OUTER JOIN
?您是否还需要从Table_1
中只选择那些column_a = 123
的行?你为什么要使用or t1.column_c IS NULL
,难道你不想要Table_1
中具有column_c = 1
的行吗?
@SameerMirji 我需要来自Table_1
的所有行,其中column_a = 123
和column_c = 1
。此外,我需要 Table_2
中没有 column_b
的所有行,这是 Table_1
到 123 中主键的一部分。这是一个多对多关系,其中 Table_1
是 @ 的关联表987654347@ 和另一张桌子。主键是Table_2
(column_b
) 和另一个表 (column_a
) 的组合。本质上,我是在尝试避免显示如果选中可能导致重复条目的行。
【参考方案1】:
根据您的评论,这应该可以回答您的问题:
SELECT Table_1.column_a, Table_1.column_b
FROM Table_1
WHERE Table_1.column_a = 123
AND Table_1.column_c = 1
UNION
SELECT Table_2.column_a, Table_2.column_b /* I'm assuming these columns exist in Table_2. Make sure these columns are same as selected columns from Table_1 */
FROM Table_2
WHERE NOT EXISTS (SELECT 1 FROM Table_1
WHERE Table_1.column_b = Table_2.column_b
AND Table_1.column_a = 123);
这在 Python SQLAlchemy 中转换为:
from sqlalchemy import exists
query_1 = (db.session.query(Table_1)
.with_entities(Table_1.column_a, Table_1.column_b)
.filter(Table_1.column_a == 123)
.filter(Table_1.column_c == 1)
query_2 = (db.session.query(Table_2)
.with_entities(Table_2.column_a, Table_2.column_b)
.filter(
~exists().where(Table_1.column_b == Table_2.column_b)
)
)
query = query_1.union(query_2).all()
【讨论】:
column_a
不包括在 Table_2
中,只有 column_b
是。但是,我认为它仍然应该主要工作。我会玩一下并试一试。但是,如果我们可以使用标准 SQL 中所示的连接来执行此操作,我更愿意。
您需要连接查询的原因是什么?由于您需要每个表中的独占行(w.r.t. column_b),因此通过连接实现这一目标并不是一个好方法。上述联合查询的 CPU 成本最低,为此执行的查询数仅为 1。
真的吗?哦,那实际上更好。出于某种原因,我认为与内联视图的连接会具有更好的性能。但我会相信你对工会的承诺并试一试。谢谢!
@ThatTechGuy:如果您发现问题已解决,您可以接受答案。 ;)
我一定会的,我只需要插入它,看看它是否返回正确的记录:)以上是关于Flask-SQLAlchemy 左外连接过滤查询的主要内容,如果未能解决你的问题,请参考以下文章