Tienes dos LEFT JOINS
:
- La primera unión a la izquierda puede unirse a varias filas desde
solved
. Diga, 'jane' y 'luke' resolvieron la tarea. - La segunda unión a la izquierda solo puede unirse a usuarios llamados 'luke' (¡'luke' en la condición de unión!).
Todavía obtienes ambos filas, 'jane' simplemente no se muestra, la condición de unión la filtra, pero LEFT JOIN
conserva la fila en el resultado de todos modos y agrega valores NULL.
Puede lograr lo que busca usando paréntesis y un [INNER] JOIN
en lugar de LEFT JOIN
entre solved
y users
. El manual:
Use paréntesis si es necesario para determinar el orden de anidamiento. En ausencia de paréntesis, JOIN
s anidan de izquierda a derecha.
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 el nombre de la tabla
users
en lugar de la palabra reservada.user
-
Suponiendo que
users.name
se define único o puede tener múltiples usuarios llamados 'luke'. -
Si
(task.id, users.id)
ensolved
se defineUNIQUE
oPRIMARY KEY
, no necesitasDISTINCT
en absoluto.
La consulta resultante no solo es correcta, sino también más rápida.
Versión SqlAlchemy de la consulta anterior: (aportado por @van)
Esto supone que Category
, Task
y User
son clases mapeadas, mientras que solved
es una instancia de Table
(solo una tabla de asociación como se muestra en el ejemplo de código 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)
)