Python SQLAlchemy在查询中获取子字符串
我有一个带有SQLite的dev数据库(也可以运行单元测试),还有一个带有MySQL的prod数据库 我需要用SQLAlchemy编写一个查询,它在WHERE语句中使用一个子字符串。我试图使用Python SQLAlchemy在查询中获取子字符串,python,sqlalchemy,Python,Sqlalchemy,我有一个带有SQLite的dev数据库(也可以运行单元测试),还有一个带有MySQL的prod数据库 我需要用SQLAlchemy编写一个查询,它在WHERE语句中使用一个子字符串。我试图使用func,但它不需要为特定的数据库引擎进行修改就可以翻译它 我的问题是: MyTable.field == func.substring_index(OtherTable.other_field, ":", 1) 所以我基本上想把一个值除以“:”并取第一部分 问题是它是用SQLite的substring\
func
,但它不需要为特定的数据库引擎进行修改就可以翻译它
我的问题是:
MyTable.field == func.substring_index(OtherTable.other_field, ":", 1)
所以我基本上想把一个值除以“:”并取第一部分
问题是它是用SQLite的
substring\u index
翻译的,这是不正确的。有没有办法在WHERE子句中使用子字符串?您可以检查数据库方言名称,并根据该名称生成子字符串。例如:
def substring(column, delimeter):
if session.bind.dialect.name == 'sqlite':
return func.substr(column, 1, func.instr(column, delimeter) - 1)
elif session.bind.dialect.name == 'mysql':
return func.substring_index(column, delimeter, 1)
然后将您的过滤条件替换为:
MyTable.field == substring(OtherTable.other_field, ":")
SQLAlchemy支持和。使用这些函数,您可以注册substring\u index()
作为一个函数,并对SQLite进行特殊处理:
from sqlalchemy.sql.functions import GenericFunction
from sqlalchemy.types import String
from sqlalchemy.ext.compiler import compiles
class substring_index(GenericFunction):
type = String
@compiles(substring_index, 'sqlite')
def compile_substring_index_sqlite(element, compiler, **kw):
s, delim, count = element.clauses
# This assumes that count is a `bindparam`, produced from passing
# literal integer to `func.substring_index()`.
assert count.value == 1, "INSTR(X, Y) only supports first occurrence"
s = compiler.process(s, **kw)
delim = compiler.process(delim, **kw)
return f"substr({s}, 1, instr({s}, {delim}) - 1)"
另一个选项是在SQLite中作为子字符串\u index()
:
有了这个函数,您可以像在MySQL中一样调用它
至于为什么这不是现成的SQLAlchemy库的一部分,这将是一场无休止的战斗,因为不同的DBMS支持完全不同的功能。例如,某些三角函数的名称各不相同,而且是现成的。在一个代码库中支持不同的SQL DBMS并非易事,而且往往不值得这样做。谢谢!我试试看!你知道为什么它不是图书馆的一部分吗?我不确定。我猜是因为每个DBMS对子字符串问题都有自己的想法和实现,而且它们并不完全兼容。
from sqlalchemy import event
def sqlite_substring_index(s, delim, count):
parts = s.split(delim)
if count > 0:
parts = parts[:count]
else:
parts = parts[count:]
return delim.join(parts)
# In your SQLite branch, before anything else DB related is performed:
@event.listens_for(engine, 'connect')
def create_functions(dbapi_connection, connection_record):
dbapi_connection.create_function('substring_index', 3, sqlite_substring_index)