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
users
zamiast zastrzeżonego słowa.user
-
Zakładając, że
users.name
jest zdefiniowany jako unikalny lub możesz mieć wielu użytkowników o nazwie „luke”. -
Jeśli
(task.id, users.id)
wsolved
jest zdefiniowanyUNIQUE
lubPRIMARY KEY
, nie potrzebujeszDISTINCT
w 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)
)