[英]Bitwise operator in SQLAlchemy: Error when using Oracle Database
我需要使用按位邏輯AND / OR編寫一些查詢,但是僅當我使用oracle數據庫時,才會收到以下錯誤:
sqlalchemy.exc.DatabaseError:(cx_Oracle.DatabaseError)ORA-01036:非法變量名稱/編號[SQL:'SELECT“ Cars”。“ Id”,“ Cars”。“ Name”,“ Cars”。“ Price” \\ nFROM “汽車” \\ nWHERE(“汽車”。“價格”&: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')OK! create_engine('oracle + cx_oracle:// xxx:yyy @ localhost:49161 / xe')錯誤!
其他操作(例如select,where子句,表創建)在所有3個數據庫中均按預期工作。
看着錯誤日志,似乎查詢未正確轉換為oracle語法。 我期待這樣的事情:
從“汽車”中選擇“汽車”。“ Id”,“汽車”。“名稱”,“汽車”。“價格”(BitAnd(“汽車”。“價格”,32768)> 0);
產生錯誤的操作是:
stm = stm.where(cars.c.Price.op('&')(0x8000)> 0)
我正在使用Python 2.7.12和SQLAlchemy == 1.1.2。
這是一個創建自定義運算符的示例,該運算符在不同的后端進行不同的編譯:
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
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.