【问题标题】:What may be the most likely cause for "ORA-00936: missing expression" in the following query generated by SQLAlchemy?在 SQLAlchemy 生成的以下查询中,“ORA-00936:缺少表达式”的最可能原因是什么?
【发布时间】:2020-01-07 06:58:57
【问题描述】:

以下错误的最可能原因是什么?我该如何解决?我不明白为什么 SQLAlchemy 会生成一个缺少表达式的查询!该代码适用于 SQLite,但在 Oracle 上失败。下面的 SQL 查询有什么问题?

此 Python 代码适用于 SQLite,但在 Oracle 11g 上失败:

q = (session.query(locomotion_class).join(LocomotionLink, LocomotionLink.parent_id == self.id).filter(LocomotionLink.child_id == locomotion_class.id, LocomotionLink.child_id != self.id))
# locomotion_class is any of the subclasses of Locomotion (in this case Virion)
return session.query(q.exists()).scalar()

以上结果如下查询:

SELECT EXISTS (
    SELECT 1
    FROM locomotion
    JOIN virion ON locomotion.id = virion.id
    JOIN locomotion_link ON locomotion_link.parent_id = 16
    WHERE locomotion_link.child_id = virion.id AND locomotion_link.child_id != 16
) AS anon_1 FROM DUAL

它在 SQLite 上工作,但在 Oracle 11g 上失败

"Internal Server Error: (cx.Oracle.DatabaseError) ORA-00936: missing expression"

当我尝试在 sqlplus 中运行生成的表达式时,它在“parent_id = 16”中显示星号低于 6(即直接在 WHERE 之前),但我看不到有任何遗漏。

【问题讨论】:

标签: python sql oracle sqlalchemy


【解决方案1】:

嗯,是的 - select exists 在 Oracle 中无效,因为它被用作 where 子句的一部分,例如

SELECT ...
  FROM ...
 WHERE EXISTS
          (SELECT 1
             FROM locomotion
                  JOIN virion ON locomotion.id = virion.id
                  JOIN locomotion_link ON locomotion_link.parent_id = 16
            WHERE     locomotion_link.child_id = virion.id
                  AND locomotion_link.child_id != 16)

另一方面,您编写的子查询表明它可能是一个 column 查询返回,例如

SELECT (SELECT 1
          FROM locomotion
               JOIN virion ON locomotion.id = virion.id
               JOIN locomotion_link ON locomotion_link.parent_id = 16
         WHERE     locomotion_link.child_id = virion.id
               AND locomotion_link.child_id != 16)
          AS anon_1
  FROM DUAL

但这有点愚蠢,因为它可能只是

SELECT 1 AS anon_1
  FROM locomotion
       JOIN virion ON locomotion.id = virion.id
       JOIN locomotion_link ON locomotion_link.parent_id = 16
 WHERE     locomotion_link.child_id = virion.id
       AND locomotion_link.child_id != 16

你应该怎么做?我不知道。这取决于您想要做什么。

【讨论】:

  • 非常感谢,您的回答非常有帮助!
【解决方案2】:

语法

SELECT EXISTS ( <a subquery> ) AS anon_1 FROM DUAL

不适合Oracle,但更喜欢使用:

SELECT 1 FROM DUAL
WHERE EXISTS 
     (
      SELECT 1
        FROM locomotion
        JOIN virion
          ON locomotion.id = virion.id
        JOIN locomotion_link
          ON locomotion_link.parent_id = 16
       WHERE locomotion_link.child_id = virion.id
         AND locomotion_link.child_id != 16
     )

【讨论】:

  • 感谢您的帮助!
【解决方案3】:

(代表问题作者发布答案,将其从问题移至答案空间)。

根据下面的评论和答案,我实施了以下修复:

return session.query(literal(True)).filter(q.exists()).scalar()

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多