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
JOIN
s 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
users
místo vyhrazeného slova.user
-
Za předpokladu, že
users.name
je definováno jako jedinečné nebo můžete mít více uživatelů pojmenovaných 'luke'. -
Pokud
(task.id, users.id)
vsolved
je definováno jakoUNIQUE
neboPRIMARY KEY
, nepotřebujeteDISTINCT
vů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)
)