Masz dwa LEFT JOINS :
- Pierwsze lewe połączenie może dołączyć do wielu wierszy z
solved. Powiedz, że „jane” i „luke” rozwiązali zadanie. - Drugie lewe dołączenie może dołączyć tylko do użytkowników o nazwie „luke” („luke” w warunku dołączenia!).
Nadal otrzymujesz oba wiersze, 'jane' po prostu nie jest pokazywana, warunek złączenia odfiltrowuje ją, ale LEFT JOIN zachowuje wiersz w wyniku i dodaje wartości NULL.
Możesz osiągnąć to, czego szukasz, używając nawiasów i [INNER] JOIN zamiast LEFT JOIN między solved i users . Instrukcja:
W razie potrzeby użyj nawiasów, aby określić kolejność zagnieżdżania. W przypadku braku nawiasów JOIN gniazdo od lewej do prawej.
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;
-
Korzystanie z nazwy tabeli
userszamiast zastrzeżonego słowa.user -
Zakładając, że
users.namejest zdefiniowany jako unikalny lub możesz mieć wielu użytkowników o nazwie „luke”. -
Jeśli
(task.id, users.id)wsolvedjest zdefiniowanyUNIQUElubPRIMARY KEY, nie potrzebujeszDISTINCTw ogóle.
Wynikowe zapytanie jest nie tylko poprawne, ale także szybsze.
Wersja SqlAlchemy powyższego zapytania: (nadesłane przez @van)
Zakłada się, że Category , Task i User są klasami mapowanymi, podczas gdy solved jest instancją Table (tylko tablica asocjacyjna, jak pokazano w przykładzie wiele do wielu):
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)
)