SQLAlchemy 支持custom SQL constructs and compilation extensions 和registering named functions。有了这些,您可以将substring_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 中将register a Python function 设置为substring_index():
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)
有了这个函数,你就可以像在 MySQL 中那样调用它了。
至于为什么这不是开箱即用的 SQLAlchemy 库的一部分,由于不同的 DBMS 支持截然不同的功能,这将是一场无休止的战斗。例如,一些三角函数的名称不同,SQLite does not provide them at all 开箱即用。在单个代码库中支持不同的 SQL DBMS 并非易事,而且往往不值得。