![](/img/trans.png)
[英]SQLAlchemy query to find and replace a substring if it exists in a column
[英]SQLAlchemy getting substring in a query
我有一個帶SQLite的dev數據庫(也可以運行該單元測試),一個帶MySQL的prod數據庫。
我需要使用SQLAlchemy編寫查詢,該查詢在WHERE語句中使用子字符串。 我試圖使用func
,但是它無需修改即可對特定的數據庫引擎進行翻譯。
我的查詢是:
MyTable.field == func.substring_index(OtherTable.other_field, ":", 1)
因此,我基本上想用“:”分割一個值並采用第一部分。
問題是它是用substring_index
轉換為SQLite的,這是不正確的。 有沒有辦法在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支持自定義SQL構造和編譯擴展以及注冊命名函數 。 通過這些,您可以將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)"
另一個選擇是將Python函數在SQLite中注冊為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根本沒有提供它們 。 在單個代碼庫中支持不同的SQL DBMS並非易事,而且常常不僅僅值得這樣做。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.