Du har två LEFT JOINS :
- Den första vänstra kopplingen kan anslutas till flera rader från
solved. Säg, "jane" och "luke" löste uppgiften. - Den andra vänstra anslutningen kan bara gå med till användare som heter 'luke' ('luke' i anslutningsvillkoret!).
Du får fortfarande båda rader, 'jane' visas bara inte, kopplingsvillkoret filtrerar bort henne, men LEFT JOIN bevarar raden i resultatet ändå och lägger till NULL-värden.
Du kan uppnå det du är ute efter genom att använda parenteser och en [INNER] JOIN istället för LEFT JOIN mellan solved och users . Manualen:
Använd parenteser om det behövs för att bestämma häckningsordningen. I avsaknad av parentes,
JOINs bo från vänster till höger.
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;
-
Använder tabellnamnet
usersistället för det reserverade ordet.users -
Förutsatt att
users.nameär definierad som unik eller så kan du ha flera användare som heter 'luke'. -
Om
(task.id, users.id)isolvedär definierad somUNIQUEellerPRIMARY KEY, du behöver inteDISTINCTöverhuvudtaget.
Den resulterande frågan är inte bara korrekt, utan också snabbare.
SqlAlchemy-versionen av ovanstående fråga: (bidraget av @van)
Detta förutsätter att Category , Task och User är mappade klasser, medan solved är en instans av Table (bara en associationstabell som visas i kodexempel 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)
)