Ответ 1
ON DUPLICATE KEY UPDATE
в операторе SQL
Если вы хотите, чтобы сгенерированный SQL действительно включал ON DUPLICATE KEY UPDATE
, самый простой способ заключается в использовании декоратора @compiles
.
Код (связанный с хорошей нитью по теме в reddit) для примера можно найти в github:
from sqlalchemy.ext.compiler import compiles
from sqlalchemy.sql.expression import Insert
@compiles(Insert)
def append_string(insert, compiler, **kw):
s = compiler.visit_insert(insert, **kw)
if 'append_string' in insert.kwargs:
return s + " " + insert.kwargs['append_string']
return s
my_connection.execute(my_table.insert(append_string = 'ON DUPLICATE KEY UPDATE foo=foo'), my_values)
Но обратите внимание, что в этом подходе вам нужно вручную создать append_string. Вероятно, вы могли бы изменить функцию append_string, чтобы она автоматически меняла строку вставки в вставку с строкой "ON DUPLICATE KEY UPDATE", но я не собираюсь делать это из-за лени.
ON DUPLICATE KEY UPDATE
в ORM
SQLAlchemy не предоставляет интерфейс для ON DUPLICATE KEY UPDATE
или MERGE
или любых других подобных функций на своем уровне ORM. Тем не менее, у него есть функция session.merge()
, которая может реплицировать функциональность только в том случае, если данный ключ является первичным ключом.
session.merge(ModelObject)
сначала проверяет, существует ли строка с тем же значением первичного ключа, отправив запрос SELECT
(или просмотрев его локально). Если это так, он устанавливает флаг где-то, указывающий, что ModelObject уже находится в базе данных, и что SQLAlchemy должен использовать запрос UPDATE
. Обратите внимание, что слияние довольно немного сложнее, чем это, но оно хорошо реплицирует функциональность с помощью первичных ключей.
Но что, если вы хотите ON DUPLICATE KEY UPDATE
функциональность с непервичным ключом (например, еще один уникальный ключ)? К сожалению, SQLAlchemy не имеет такой функции. Вместо этого вам нужно создать что-то похожее на Django get_or_create()
. fooobar.com/questions/15346/..., и я просто добавлю измененную рабочую версию этого здесь для удобства.
def get_or_create(session, model, defaults=None, **kwargs):
instance = session.query(model).filter_by(**kwargs).first()
if instance:
return instance
else:
params = dict((k, v) for k, v in kwargs.iteritems() if not isinstance(v, ClauseElement))
if defaults:
params.update(defaults)
instance = model(**params)
return instance