2016-11-01 27 views
0

,當我需要使用逐邏輯來寫一些查詢和/或,但只有當我使用Oracle數據庫,我收到以下錯誤:位運算符在SQLAlchemy中:錯誤使用Oracle數據庫

sqlalchemy.exc.DatabaseError: (cx_Oracle.DatabaseError) ORA-01036: illegal variable name/number [SQL: 'SELECT "Cars"."Id", "Cars"."Name", "Cars"."Price" \nFROM "Cars" \nWHERE ("Cars"."Price" & :Price_1) > :param_1'] [parameters: {'Price_1': 32768, 'param_1': 0}]

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

create_engine('sqlite:///cars.sqlite3') OK! create_engine('postgresql+psycopg2://xxx:[email protected]:5432/db_sql_alchemy') OK! create_engine('oracle+cx_oracle://xxx:[email protected]:49161/xe') ERROR!

其他操作,如select,where子句,表創建,在所有3個數據庫中按預期工作。

看着錯誤日誌,似乎查詢沒有被正確地翻譯成oracle語法。我期待這樣的事情:

SELECT "Cars"."Id", "Cars"."Name", "Cars"."Price" FROM "Cars" WHERE (BitAnd("Cars"."Price", 32768) > 0);

生成錯誤的操作:

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

我使用Python 2.7.12和SQLAlchemy的== 1.1.2。

+1

甲骨文不會出現有'&'操作。試試['BITAND'](http://docs.oracle.com/cd/B28359_01/server.111/b28286/functions014.htm#SQLRF00612)函數。 – univerio

+0

'op()'泛型呈現原樣。沒有涉及翻譯(iirc)。你有你要求的。 –

+0

感謝您的回答,但我正在使用sqlalchemy -SQL表達式語言。我想,對於任何數據庫選擇,按位操作的語法都是相同的。我想跳過編寫原始的sql,因爲我需要使用多個數據庫。 – user3632887

回答

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 
+0

非常感謝!這是我使用SqlAlchemy的第一個項目,這個過程對我來說並不明確。 – user3632887