2015-10-15 5 views
5

Lavorando con MySQL, mi piacerebbe per generare questo SQL:Aggiornamento unito tabella tramite SQLAlchemy ORM utilizzando session.query

UPDATE tableA 
INNER JOIN tableB 
ON tableA.some_id = tableB.some_id 
SET tableA.foo = 1 
WHERE tableB.bar IN ('baz','baaz') 

Questa è la mia interrogazione SQLAlchemy:

session.query(tableA).join(tableB, tableA.some_id == tableB.some_id) \ 
        .filter(tableB.bar.in_(['baz','baaz']))\ 
        .update({tableA.foo: 1}) 

Ma l'SQL è genera è questo (un aggiornamento multi-tavolo, senza alcuna condizione di join, che non è quello che voglio):

UPDATE tableA, tableB 
SET tableA.foo = 1 
WHERE tableB.bar IN ('baz','baaz') 

ho provato a cambiare il .j oin in un altro .filter per specificare la condizione di join, che non ha risolto il problema. Come posso forzare questa semplice istruzione di aggiornamento a fare il join corretto?

+0

Hai risolto il problema? Ho qualcosa di quasi identico e sto lottando – Fuxi

+0

Dovevo andare avanti con una soluzione alternativa (due query invece di una). Evita la domanda se stai lottando con lo stesso, forse qualcuno lo vedrà. – ValAyal

risposta

3

A partire dalla versione 0.7.4 sqlalchemy.sql.expression.update non consentono di fare riferimento a più tabelle nella clausola WHERE. Con questo, si potrebbe costruire ed eseguire un'espressione del tipo:

users.update().values(name='ed').where(
     users.c.name==select([addresses.c.email_address]).\ 
        where(addresses.c.user_id==users.c.id).\ 
        as_scalar() 
     ) 

(ad esempio direttamente dal link qui sotto)

Il problema ValAyal sta avendo in realtà è perché Query.join() non è supportata con Query.update(). Sfortunatamente, fino alla 0.9.1 questo ha generato silenziosamente query come quella condivisa da ValAyal sopra. Le changelog notes for 0.9.1 note che il comportamento è stato modificato per emettere un avvertimento:

[orm] [Bug] Query non supporta unisce, subselect, o speciali da clausole quando si utilizza il Query.update() o query. metodi delete(); invece di ignorare silenziosamente questi campi se sono stati chiamati metodi come Query.join() o Query.select_from(), viene emesso un avviso. A partire da 1.0.0b5 si genera un errore.

Riferimenti: #3349

Noi in realtà sono imbattuto in questo dove lavoro proprio questa sera e abbiamo trovato che il nostro codice è, infatti, emette il seguente avviso (che dice che un errore in 1.0):

SAWarning: Can't call Query.update() or Query.delete() when join(), outerjoin(), select_from(), or from_self() has been called. This will be an exception in 1.0 
    self._validate_query_state() 

Nel nostro caso, abbiamo deciso di convertire l'aggiornamento in una selezione e un aggiornamento a una tabella

+0

Si noti che l'esempio qui non è un aggiornamento a più tabelle, ma il metodo SQL standard per fare riferimento a più tabelle utilizzando una query secondaria. –

0

Penso di aver avuto esattamente lo stesso problema. Qui è la mia soluzione:

query = update(Model).values(field=123) 
query = query.where(Model.parent_model_id == ParentModel.id) 
query = query.where(ParentModel.grand_parent_id == GrandParentModel.id) 
query = query.where(GrandParentModel.name == 'foobar') 
session.execute(query)