Máte dvě LEFT JOINS :
- První levé spojení se může připojit k více řádkům z
solved. Řekněme, že 'jane' a 'luke' vyřešili úkol. - Druhé levé připojení se může připojit pouze k uživatelům jménem 'luke' ('luke' v podmínce připojení!).
Stále máte obě řádky, 'jane' se prostě nezobrazuje, podmínka spojení ji odfiltruje, ale LEFT JOIN stejně zachová řádek ve výsledku a připojí hodnoty NULL.
Pomocí závorek můžete dosáhnout toho, po čem toužíte a [INNER] JOIN místo LEFT JOIN mezi solved a users . Manuál:
V případě potřeby použijte k určení pořadí vnoření závorky. Při absenci závorek
JOINs hnízdo zleva doprava.
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;
-
Použití názvu tabulky
usersmísto vyhrazeného slova.user -
Za předpokladu, že
users.nameje definováno jako jedinečné nebo můžete mít více uživatelů pojmenovaných 'luke'. -
Pokud
(task.id, users.id)vsolvedje definováno jakoUNIQUEneboPRIMARY KEY, nepotřebujeteDISTINCTvůbec.
Výsledný dotaz je nejen správný, ale také rychlejší.
Verze SqlAlchemy výše uvedeného dotazu: (přispěl @van)
To předpokládá, že Category , Task a User jsou mapované třídy, zatímco solved je instancí Table (pouze asociační tabulka, jak je ukázáno v příkladu kódu 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)
)