SQLAlchemy呈现的SQL中的语法错误

时间:2014-03-17 17:52:50

标签: mysql sqlalchemy

我试图在SQLAlchemy中复制此查询:

select date,
sum(case when country = 'USA' or country like '%merica' then dollars else 0 end),
sum(case when country  != 'USA' and country not like '%merica' then dollars else 0 end)
from Spend
group date;

所以,我有以下查询对象:

q = connection.session.query(Spend.date, \
        func.sum(func.case([ ( (Spend.country == 'USA') | (Spend.country.like('%merica') ), Spend.dollars ) ], else_ = 0) ), \
        func.sum(func.case([ ( (Spend.country != 'USA') & (~Spend.country.like('%merica') ), Spend.dollars ) ], else_ = 0) )) \
        .group_by(Spend.date)

当我运行此查询时,我收到以下异常:

sqlalchemy.exc.ProgrammingError: (ProgrammingError)
(1064, 'You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near
\'))) AS sum_1, sum(case(((\\\\"Spend\\\\".country != :na\' at line 1')

因此,显然在查询的呈现方面存在一些打嗝。但是,MySQL不会使用无效语法记录查询,当我在python中打印查询时,我得到它:

SELECT Spend.date AS Spend_Date, sum(case(%s)) AS sum_1, sum(case(%s)) AS sum_2
FROM Spend GROUP BY Spend.date
([(<sqlalchemy.sql.expression.BooleanClauseList object at 0xff6a7dec>, <sqlalchemy.orm.attributes.InstrumentedAttribute object at 0xff86f1ac>)], [(<sqlalchemy.sql.expression.BooleanClauseList object at 0xff6a7fec>, <sqlalchemy.orm.attributes.InstrumentedAttribute object at 0xff86f1ac>)])

我的问题有两个:我怎样才能看到呈现的查询是什么样的? (不幸的是,这个答案https://stackoverflow.com/a/5698357/125193没有帮助,因为它无法呈现BooleanClauseList)。另外,有没有人对我的查询可能有什么问题有任何提示?

谢谢!

更新

我能够对错误处理程序进行修补,以更好地了解正在呈现的SQL。

def wrap_handler(self, e, statement, parameters, cursor, context):
    # Note: MySQLdb-specific
    print(cursor._last_executed)
    self.__handle_dbapi_exception(e, statement, parameters, cursor, context)

import types
connection.session.connection().__handle_dbapi_exception = connection.session.connection()._handle_dbapi_exception
connection.session.connection()._handle_dbapi_exception = types.MethodType(wrap_handler, connection.session.connection())

这是SQL:

SELECT `Spend`.date AS `Spend_date`,
sum(case((('\'\\"Spend\\".country = :name_1 OR \\"Spend\\".country LIKE :name_2\'', "'Spend.dollars'"),))) AS sum_1,
sum(case((('\'\\"Spend\\".country != :name_1 AND \\"Spend\\".country NOT LIKE :name_2\'', "'Spend.dollars'"),))) AS sum_2
FROM Spend
GROUP BY Spend.date

我仍然缺少实际参数,但很明显,SQL已经搞砸了。我将重新阅读func.case的文档。

1 个答案:

答案 0 :(得分:1)

似乎func周围有一些严重的黑魔法。您可以调用func.anything_at_all,SQLAlchemy将尝试将其转换为有效的SQL。诀窍是分别导入case,然后直接调用它。

from sqlalchemy import case, func
# ...
func.sum(case([ ( (Spend.country == 'USA') | (Spend.country.like('%merica') ), Spend.dollars ) ], else_ = 0) )
# Notice that func.case is now just case

现在一切都按预期工作。