Hai due LEFT JOINS :
- Il primo join a sinistra può unire a più righe da
solved. Dì, "jane" e "luke" hanno risolto il compito. - Il secondo join a sinistra può unirsi solo agli utenti di nome 'luke' ('luke' nella condizione di join!).
Ottieni ancora entrambi righe, 'jane' non viene mostrata, la condizione di unione la filtra, ma LEFT JOINS conserva comunque la riga nel risultato e aggiunge valori NULL.
Puoi ottenere ciò che cerchi utilizzando le parentesi e un [INNER] JOIN invece di LEFT JOINS tra solved e users . Il manuale:
Utilizzare le parentesi se necessario per determinare l'ordine di annidamento. In assenza di parentesi, JOIN s annida da sinistra a destra.
SELECT c.name AS cat_name, t.name AS task_name, u.name AS user_name
FROM task t
JOIN category c ON cat.id = t.category_id
LEFT JOIN
(solved s JOIN users u ON u.id = s.user_id AND u.name = 'luke') ON s.task_id = t.id
ORDER BY 1, 2, 3;
-
Usando il nome della tabella
usersal posto della parola riservata.user -
Supponendo che
users.nameè definito unico oppure puoi avere più utenti chiamati 'luke'. -
Se
(task.id, users.id)insolvedè definitoUNIQUEoPRIMARY KEY, non hai bisogno diDISTINCTaffatto.
La query risultante non è solo corretta, ma anche più veloce.
Versione SQLAlchemy della query precedente: (contributo di @van)
Ciò presuppone che Category , Task e User sono classi mappate, mentre solved è un'istanza di Table (solo una tabella di associazione come mostrato nell'esempio di codice Many to Many):
user_name = 'luke'
q = (session.query(Category.name, Task.name, User.name)
.select_from(Task)
.join(Category)
.outerjoin(
join(solved, User,
(solved.c.user_id == User.id) & (User.name == user_name),
))
.order_by(Category.name, Task.name, User.name)
)