SQLAlchemy中的按位运算符:使用Oracle数据库时出错

时间:2016-11-01 16:57:57

标签: python oracle11g sqlalchemy

我需要使用按位逻辑AND / OR编写一些查询,但只有当我使用oracle数据库时,才会收到以下错误:

  

sqlalchemy.exc.DatabaseError:(cx_Oracle.DatabaseError)ORA-01036:   非法变量名称/编号[SQL:' SELECT" Cars"。" Id",   "汽车"。"名称","汽车"。"价格" \ nFROM"汽车" \ n WHERHER(" Cars"。" Price"&   :Price_1)> :param_1'] [参数:{' Price_1':32768,' param_1':0}]

如果我使用PostgreSql或Sqlite,我会收到预期的答案。

  

create_engine(' sqlite:///cars.sqlite3')好的!   create_engine(' postgresql + psycopg2:// xxx:yyy @ localhost:5432 / db_sql_alchemy')好的! create_engine('预言+ cx_oracle:// XXX:YYY @本地:49161 / XE')   ERROR!

其他操作,例如select,where子句,表创建,在所有3个数据库中按预期工作。

观察错误日志,似乎查询未正确转换为oracle语法。我期待这样的事情:

  

SELECT" Cars"。" Id"," Cars"。" Name"," Cars"。& #34;价格"来自"汽车"哪里   (BitAnd(" Cars"。" Price",32768)> 0);

生成错误的操作是:

  

stm = stm.where(cars.c.Price.op('&')(0x8000)> 0)

我正在使用Python 2.7.12和SQLAlchemy == 1.1.2。

1 个答案:

答案 0 :(得分:0)

以下是创建在不同后端编译不同的自定义运算符的示例:

from sqlalchemy.ext.compiler import compiles
from sqlalchemy.sql.elements import ColumnElement, Visitable, Grouping
from sqlalchemy.sql.operators import custom_op, is_precedent

class BitwiseAnd(ColumnElement):
    type = Integer()
    operator = custom_op("&", precedence=6)

    def __init__(self, left, right):
        if not isinstance(left, Visitable):
            left = bindparam("bitand", left, unique=True)
        if not isinstance(right, Visitable):
            right = bindparam("bitand", right, unique=True)
        self.left = left
        self.right = right

    def self_group(self, against=None):
        if is_precedent(self.operator, against):
            return Grouping(self)
        else:
            return self


@compiles(BitwiseAnd)
def _compile_bitwise_and(element, compiler, **kwargs):
    left = element.left.self_group(against=element.operator)
    right = element.right.self_group(against=element.operator)
    return compiler.process(element.operator(left, right))


@compiles(BitwiseAnd, "oracle")
def _compile_bitwise_and_oracle(element, compiler, **kwargs):
    return compiler.process(func.BITAND(element.left, element.right))

q = select([BitwiseAnd(BitwiseAnd(1, 2), BitwiseAnd(3, 4))])
print(q.compile(dialect=mysql.dialect()))
# SELECT (%s & %s) & (%s & %s) AS anon_1
print(q.compile(dialect=oracle.dialect()))
# SELECT BITAND(BITAND(:bitand_1, :bitand_2), BITAND(:bitand_3, :bitand_4)) AS anon_1 FROM DUAL