Flask-SQLAlchemy 左外连接过滤查询

Posted

技术标签:

【中文标题】Flask-SQLAlchemy 左外连接过滤查询【英文标题】:Flask-SQLAlchemy Left Outer Join Filtered Query 【发布时间】:2016-05-08 16:14:11 【问题描述】:

最初我试图做一个“右外连接”,但一旦我发现它不受支持,我就开始从左边开始工作。但是,我很难弄清楚如何写出我需要的东西。基本上我有两个表,Table_1Table_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 = 123column_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 左外连接过滤查询的主要内容,如果未能解决你的问题,请参考以下文章

左外连接还是 where 语句?

左外连接,右外连接,全外连接

Linq To Sql 左外连接 - 过滤空结果

如何在 obiee 的左外连接的一部分中包含分析过滤器(左连接变为内连接)

LINQ查询中的左外连接[重复]

如何强制 Hibernate 在组件上使用左外连接进行命名查询?