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,
JOIN
s 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
users
istä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 somUNIQUE
ellerPRIMARY 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)
)