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
users
al posto della parola riservata.user
-
Supponendo che
users.name
è definito unico oppure puoi avere più utenti chiamati 'luke'. -
Se
(task.id, users.id)
insolved
è definitoUNIQUE
oPRIMARY KEY
, non hai bisogno diDISTINCT
affatto.
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)
)