2013-02-22 3 views
1

Я пытаюсь воспроизвести следующий запрос в SQLAlchemy + MySQL без везения ...SQLAlchemy: Создать запрос на удаление с помощью автообъединения на MySQL

delete paths from paths 
join paths as p1 on p1.ancestor = <ID> 
where paths.descendant = p1.descendant; 

SQLAlchemy кажется бы игнорируя любые объединения, которые я вложил в запрос удаления. Я также попытался использовать подзапрос вместо соединения, но это не разрешено в MySQL (невозможно выбрать из той же таблицы, которую вы хотите удалить). Любая помощь приветствуется.

Обновление: Да, я пытаюсь использовать слой ORM. Вот те запросы, которые я пробовал:

p1 = aliased(Path, name="p1") 
db.session.query(Path).join(
    p1, p1.ancestor==<ID> 
) 
.filter(
    Path.descendant==p1.Path.descendant 
).delete() 

а подзапрос вариант, но это не работает на MySQL, так что это не имеет смысла для меня:

q = db.session.query(Path.descendant).filter(Path.ancestor==<ID>).subquery() 
db.session.query(Path).filter(Path.descendant.in_(q)).delete(synchronize_session='fetch') 
+0

Вы используете слой orm или sql? Можете ли вы включить фрагмент, который вы попробовали? –

+0

ORM, но с удовольствием используем все, что помогает нам достичь запроса. Я обновил свой вопрос с неудачными попытками. – Ole

+0

Связанный: https://stackoverflow.com/questions/25395756/sqlalchemy-how-to-delete-with-join –

ответ

2

SQLAlchemy в настоящее время поддерживает UPDATE. .FROM через Postgresql, MySQL и другие, но мы еще не пытались поддерживать DELETE..JOIN.

Однако он появляется на работе, насколько генерации SQL строки (почти?):

class Path(Base): 
    __tablename__ = "path" 

    id = Column(Integer, primary_key=True) 
    descendant = Column(Integer) 
    ancestor = Column(Integer) 

j = join(Path, p1, p1.ancestor == 5) 
d = delete(j).where(Path.descendant == p1.descendant) 
print d 

печатает:

DELETE FROM path JOIN path AS p1 ON p1.ancestor = :ancestor_1 
WHERE path.descendant = p1.descendant 

Однако моя база данных MySQL не принимает это по умолчанию он оказывает INNER JOIN, которая выходит из строя, но если я могу изменить компилятор MySQL, чтобы не делать этого, до сих пор не удается:

s.execute(d) 

(ProgrammingError) (1064, "You have an error in your SQL syntax; check the manual that 
corresponds to your MySQL server version for the 
right syntax to use near 'JOIN path AS p1 ON p1.ancestor = 5 WHERE 
path.descendant = p1.descendant' at line 1") 'DELETE FROM path JOIN 
path AS p1 ON p1.ancestor = %s WHERE path.descendant = p1.descendant' 
(5,) 

выглядит как ваш SQL verbatim (oh, за исключением 'delete paths FROM paths'? это правильно?) ?

В любом случае, если встроенный компилятор не делает этого, ваши варианты должны использовать session.execute("some sql") или построить пользовательскую конструкцию с помощью compiler extension.

+0

Привет, спасибо за это. Не уверен, что это относится ко всем базам данных, но да, MySQL требует «DELETE ** paths ** FROM paths». Почти там! – Ole

+0

он не распространяется на любую другую базу данных. MySQL имеет много и много синтаксисов, которые полностью являются их собственным изобретением. – zzzeek

2

Вы можете использовать prefixes аргумент ключевое слово:

j = join(table1, table2, table1.c.key==table2.c.key) 
stmt = delete(j, prefixes=[table1_name]) 
session.execute(stmt) 

prefixes ключевое слово просто добавляет один или несколько выражений, следующие за ключевым словом заявление, т.е. SELECT, INSERT, UPDATE, DELETE или.

В этом случае оператор delete(j) генерирует выражение: "DELETE FROM table1 INNER JOIN table2 ON table1.key=table2.key". Когда мы добавляем выражение prefixes, выражение становится: "DELETE table1 FROM table1 INNER JOIN table2 ON table1.key=table2.key", то есть правильный запрос MySQL.