SQLAlchemy Left join WHERE 子句被转换为零和一

Posted

技术标签:

【中文标题】SQLAlchemy Left join WHERE 子句被转换为零和一【英文标题】:SQLAlchemy Left join WHERE clause being converted to zeros and ones 【发布时间】:2016-04-11 01:41:18 【问题描述】:

你好,

我有以下 SQL,我正在转换为 SQLAlchemy:

select t1.`order_id`, t1.`status_type`
from `tracking_update` AS t1 LEFT JOIN `tracking_update` AS t2
ON (t1.`order_id` = t2.`order_id` AND t1.`last_updated` < t2.`last_updated`)
where t1.`order_id` = '21757'and t2.`last_updated` IS NULL

SQL 只是返回订单 id 21757 的最新跟踪更新。我通过将左连接返回到同一个表来完成此操作。为了做到这一点,我首先给表起别名:

        tUAlias1 = aliased(TrackingUpdate)
        tUalias2 = aliased(TrackingUpdate)

到目前为止,这就是我转换为 SQLAlchemy 的过程:

tracking_updates = db.session.query(tUAlias1.order_id, tUAlias1.status_type).\
            outerjoin(tUalias2, (tUAlias1.order_id == tUalias2.order_id) & (tUAlias1.last_updated < tUalias2.last_updated)).\
            filter(and_(tUAlias1.order_id == '21757', tUalias2.last_updated is None))

这是通过日志在服务器上执行的 SQLAlchemy 代码的结果:

SELECT tracking_update_1.order_id AS tracking_update_1_order_id, tracking_update_1.status_type AS tracking_update_1_status_type 
FROM tracking_update AS tracking_update_1 LEFT OUTER JOIN tracking_update AS tracking_update_2 ON tracking_update_1.order_id = tracking_update_2.order_id AND tracking_update_1.last_updated < tracking_update_2.last_updated 
WHERE 0 = 1

如您所见,过滤器(WHERE 子句)现在为 0 = 1。

现在,如果我删除 and_ 语句并尝试两个过滤器,如下所示:

tracking_updates = db.session.query(tUAlias1.order_id, tUAlias1.status_type).\
            outerjoin(tUalias2, (tUAlias1.order_id == tUalias2.order_id) & (tUAlias1.last_updated < tUalias2.last_updated)).\
            filter(tUAlias1.order_id == '21757').filter(tUalias2.last_updated is None)

我收到相同的结果。我知道 SQL 本身很好,因为我可以通过 mysql 工作台毫无问题地运行它。

当SQL直接运行时,我会收到以下信息

order ID | Status
21757      D

另外,如果我删除 tUalias2.last_updated is None,我实际上会收到一些结果,但它们不正确。这是它的 SQL 日志:

Python 代码

tracking_updates = db.session.query(tUAlias1.order_id, tUAlias1.status_type).\
            outerjoin(tUalias2, (tUAlias1.order_id == tUalias2.order_id) & (tUAlias1.last_updated < tUalias2.last_updated)).\
            filter(tUAlias1.order_id == '21757')

SQLAlchemy 运行:

SELECT tracking_update_1.order_id AS tracking_update_1_order_id, tracking_update_1.status_type AS tracking_update_1_status_type 
FROM tracking_update AS tracking_update_1 LEFT OUTER JOIN tracking_update AS tracking_update_2 ON tracking_update_1.order_id = tracking_update_2.order_id AND tracking_update_1.last_updated < tracking_update_2.last_updated 
WHERE tracking_update_1.order_id = '21757'

有什么想法吗?

【问题讨论】:

【参考方案1】:

你好,

我想通了

Python 'is' 运算符不能很好地与 SQLAlchemy 配合使用

感谢以下 S/O 问题,我发现了这一点:

Selecting Null values SQLAlchemy

我已将我的查询更新为以下内容:

tracking_updates = db.session.query(tUAlias1.order_id, tUAlias1.status_type).\
            outerjoin(tUalias2, (tUAlias1.order_id == tUalias2.order_id) & (tUAlias1.last_updated < tUalias2.last_updated)).\
            filter(tUAlias1.order_id == '21757').filter(tUalias2.last_updated == None)

【讨论】:

【参考方案2】:

问题不在于 SqlAlchemy 如何处理空值,问题在于您使用了 instrumented' columns and thus the expressiontUalias2.last_updated 不支持的运算符 Noneevaluates to a value (False), which is then translated to eitherand 0=1. You should writetUalias2.last_updated.is_ (None)instead oftUalias2.last_updated 是 None` 以使您的代码正常工作。

【讨论】:

以上是关于SQLAlchemy Left join WHERE 子句被转换为零和一的主要内容,如果未能解决你的问题,请参考以下文章

MYSQL 语法错误 LEFT JOIN

SQL语句的执行顺序

sql语句执行顺序、

flask_sqlalchemy join的正确使用方法

四十四:数据库之SQLAlchemy之join实现复杂查询

如何从 SQLAlchemy JOIN 中的两个表返回结果?